diff --git a/jte/src/main/java/gg/jte/compiler/TemplateParser.java b/jte/src/main/java/gg/jte/compiler/TemplateParser.java index 50449ecb..23dd0aca 100644 --- a/jte/src/main/java/gg/jte/compiler/TemplateParser.java +++ b/jte/src/main/java/gg/jte/compiler/TemplateParser.java @@ -754,11 +754,22 @@ private void interceptHtmlTags() { visitor.onError("Unclosed tag <" + currentHtmlTag.name + ">, expected " + "" + currentHtmlTag.name + ">, got " + tagName + ">."); } tagClosed = true; - } else if (!currentHtmlTag.attributesProcessed && !Character.isWhitespace(currentChar) && currentChar != '/' && currentHtmlTag.isCurrentAttributeComplete()) { + } else if (!currentHtmlTag.attributesProcessed && !Character.isWhitespace(currentChar) && currentChar != '/' && currentChar != '=' && currentHtmlTag.isCurrentAttributeComplete()) { HtmlAttribute attribute = parseHtmlAttribute(); if (attribute != null) { htmlPolicy.validateHtmlAttribute(currentHtmlTag, attribute); + if (attribute.name.startsWith("$unsafe{")) { + i += "$unsafe".length() - 1; + outputPrevented = false; + return; + } + + if (attribute.name.startsWith("${")) { + outputPrevented = false; + return; + } + currentHtmlTag.attributes.add(attribute); if (attribute.isSmartAttribute()) { diff --git a/jte/src/test/java/gg/jte/TemplateEngine_HtmlOutputEscapingTest.java b/jte/src/test/java/gg/jte/TemplateEngine_HtmlOutputEscapingTest.java index 3bb24fd1..f6073ebe 100644 --- a/jte/src/test/java/gg/jte/TemplateEngine_HtmlOutputEscapingTest.java +++ b/jte/src/test/java/gg/jte/TemplateEngine_HtmlOutputEscapingTest.java @@ -1704,6 +1704,24 @@ void attributes_dynamicNameForHotwire_unsafe_worksWithDefaultPolicyToo() { assertThat(output.toString()).isEqualTo("