");
+
+ var attr = tokens[0].Attributes.Single();
+ Assert.Equal("class", attr.Name);
+ Assert.Equal("foo", attr.Value);
+ }
+
+ ///
+ /// An inline style attribute is preserved in its entirety.
+ ///
+ [Fact]
+ public void InlineStyleAttribute_IsPreserved()
+ {
+ var tokens = Tokenize("
");
+
+ var attr = tokens[0].Attributes.Single();
+ Assert.Equal("style", attr.Name);
+ Assert.Equal("color: red; font-size: 14px;", attr.Value);
+ }
+
+ ///
+ /// A stray less-than character is emitted as text.
+ ///
+ [Fact]
+ public void StrayLessThan_IsEmittedAsText()
+ {
+ var tokens = Tokenize("a < b");
+
+ Assert.Equal(HtmlTokenType.Text, tokens[0].Type);
+ Assert.Equal("a ", tokens[0].Value);
+ Assert.Equal(HtmlTokenType.Text, tokens[1].Type);
+ Assert.Equal("<", tokens[1].Value);
+ Assert.Equal(HtmlTokenType.Text, tokens[2].Type);
+ }
+
+ ///
+ /// A keygen void element without slash is emitted as self-closing.
+ ///
+ [Fact]
+ public void KeygenVoidElement_ReturnsSelfClosing()
+ {
+ var tokens = Tokenize("");
+
+ Assert.Equal(HtmlTokenType.SelfClosingTag, tokens[0].Type);
+ Assert.Equal("keygen", tokens[0].TagName);
+ }
}
}
diff --git a/src/WebExpress.WebCore/WebHtml/Parser/HtmlElementFactory.cs b/src/WebExpress.WebCore/WebHtml/Parser/HtmlElementFactory.cs
index 96c5bc5..2c5251b 100644
--- a/src/WebExpress.WebCore/WebHtml/Parser/HtmlElementFactory.cs
+++ b/src/WebExpress.WebCore/WebHtml/Parser/HtmlElementFactory.cs
@@ -77,6 +77,10 @@ public class HtmlElementFactory
["dfn"] = () => new HtmlElementTextSemanticsDfn(),
["em"] = () => new HtmlElementTextSemanticsEm(),
["i"] = () => new HtmlElementTextSemanticsI(),
+ // The standard HTML element is , but the existing class uses "kdb" as
+ // its element name. Both spellings are mapped so that the parser handles
+ // real-world HTML () as well as the project's own renderer output ().
+ ["kbd"] = () => new HtmlElementTextSemanticsKdb(),
["kdb"] = () => new HtmlElementTextSemanticsKdb(),
["mark"] = () => new HtmlElementTextSemanticsMark(),
["q"] = () => new HtmlElementTextSemanticsQ(),
@@ -138,6 +142,7 @@ public class HtmlElementFactory
["datalist"] = () => new HtmlElementFormDatalist(),
["fieldset"] = () => new HtmlElementFormFieldset(),
["form"] = () => new HtmlElementFormForm(),
+ ["keygen"] = () => new HtmlElementFormKeygen(),
["meter"] = () => new HtmlElementFormMeter(),
["optgroup"] = () => new HtmlElementFormOptgroup(),
["option"] = () => new HtmlElementFormOption(),
@@ -146,6 +151,7 @@ public class HtmlElementFactory
["textarea"] = () => new HtmlElementFormTextarea(),
// Interactive
+ ["command"] = () => new HtmlElementInteractiveCommand(),
["details"] = () => new HtmlElementInteractiveDetails(),
["menu"] = () => new HtmlElementInteractiveMenu(),
["summary"] = () => new HtmlElementInteractiveSummary(),
diff --git a/src/WebExpress.WebCore/WebHtml/Parser/HtmlTokenizer.cs b/src/WebExpress.WebCore/WebHtml/Parser/HtmlTokenizer.cs
index d835cde..b96e085 100644
--- a/src/WebExpress.WebCore/WebHtml/Parser/HtmlTokenizer.cs
+++ b/src/WebExpress.WebCore/WebHtml/Parser/HtmlTokenizer.cs
@@ -28,7 +28,7 @@ public class HtmlTokenizer
new(StringComparer.OrdinalIgnoreCase)
{
"area", "base", "br", "col", "embed", "hr", "img", "input",
- "link", "meta", "param", "source", "track", "wbr"
+ "keygen", "link", "meta", "param", "source", "track", "wbr"
};
///