@@ -35,7 +35,8 @@ final class Escaper
3535 HtmlBogusTag = 'html/bogus ' ,
3636 HtmlRawText = 'html/raw ' ,
3737 HtmlTag = 'html/tag ' ,
38- HtmlAttribute = 'html/attr ' ;
38+ HtmlAttribute = 'html/attr ' ,
39+ HtmlAttributeExpression = 'html/attr-e ' ;
3940
4041 private const Convertors = [
4142 self ::Text => [
@@ -154,7 +155,7 @@ public function enterHtmlRaw(string $subType): void
154155
155156 public function enterHtmlAttribute (?string $ name , bool $ expression = false ): void
156157 {
157- $ this ->state = self ::HtmlAttribute;
158+ $ this ->state = $ expression ? self ::HtmlAttributeExpression : self ::HtmlAttribute;
158159 $ this ->subType = '' ;
159160
160161 if ($ this ->contentType === ContentType::Html && is_string ($ name )) {
@@ -166,8 +167,9 @@ public function enterHtmlAttribute(?string $name, bool $expression = false): voi
166167 } elseif ($ expression && ((in_array ($ name , ['href ' , 'src ' , 'action ' , 'formaction ' ], true )
167168 || ($ name === 'data ' && strcasecmp ($ this ->tag , 'object ' ) === 0 )))
168169 ) {
169- $ this ->subType = self ::Url;
170+ $ this ->subType = self ::Url; // TODO: jen simple, jako AttributeUrl
170171 }
172+ // TODO: AttributeBool, AttributeList, AttributeData, AttributeAria
171173 }
172174 }
173175
@@ -191,11 +193,16 @@ public function escape(string $str): string
191193 self ::HtmlText => 'LR\HtmlHelpers::escapeText( ' . $ str . ') ' ,
192194 self ::HtmlTag => 'LR\HtmlHelpers::escapeTag( ' . $ str . ') ' ,
193195 self ::HtmlAttribute => match ($ this ->subType ) {
194- '' ,
195- self ::Url => 'LR\HtmlHelpers::escapeAttr( ' . $ str . ') ' ,
196+ '' => 'LR\HtmlHelpers::escapeAttr( ' . $ str . ') ' ,
196197 self ::JavaScript => 'LR\HtmlHelpers::escapeAttr(LR\Helpers::escapeJs( ' . $ str . ')) ' ,
197198 self ::Css => 'LR\HtmlHelpers::escapeAttr(LR\Helpers::escapeCss( ' . $ str . ')) ' ,
198199 },
200+ self ::HtmlAttributeExpression => match ($ this ->subType ) {
201+ '' ,
202+ self ::Url => 'LR\HtmlHelpers::formatAttributeValue( ' . $ str . ') ' ,
203+ self ::JavaScript => 'LR\HtmlHelpers::formatAttributeValue(LR\Helpers::escapeJs( ' . $ str . ')) ' ,
204+ self ::Css => 'LR\HtmlHelpers::formatAttributeValue(LR\Helpers::escapeCss( ' . $ str . ')) ' ,
205+ },
199206 self ::HtmlComment => 'LR\HtmlHelpers::escapeComment( ' . $ str . ') ' ,
200207 self ::HtmlBogusTag => 'LR\HtmlHelpers::escapeTag( ' . $ str . ') ' ,
201208 self ::HtmlRawText => match ($ this ->subType ) {
@@ -210,6 +217,7 @@ public function escape(string $str): string
210217 self ::HtmlText => 'LR\XmlHelpers::escapeText( ' . $ str . ') ' ,
211218 self ::HtmlBogusTag => 'LR\XmlHelpers::escapeTag( ' . $ str . ') ' ,
212219 self ::HtmlAttribute => 'LR\XmlHelpers::escapeAttr( ' . $ str . ') ' ,
220+ self ::HtmlAttributeExpression => 'LR\XmlHelpers::formatAttributeValue( ' . $ str . ') ' ,
213221 self ::HtmlComment => 'LR\HtmlHelpers::escapeComment( ' . $ str . ') ' ,
214222 self ::HtmlTag => 'LR\XmlHelpers::escapeTag( ' . $ str . ') ' ,
215223 default => throw new \LogicException ("Unknown context $ this ->contentType , $ this ->state . " ),
@@ -228,6 +236,7 @@ public function escapeMandatory(string $str, ?Position $position = null): string
228236 return match ($ this ->contentType ) {
229237 ContentType::Html => match ($ this ->state ) {
230238 self ::HtmlAttribute => "LR \\HtmlHelpers::escapeQuotes( $ str) " ,
239+ self ::HtmlAttributeExpression => "' \"' . LR \\HtmlHelpers::escapeQuotes( $ str) . ' \"' " ,
231240 self ::HtmlRawText => match ($ this ->subType ) {
232241 self ::HtmlText => 'LR\HtmlHelpers::convertHtmlToRawText( ' . $ str . ') ' ,
233242 default => "LR \\HtmlHelpers::convertJSToRawText( $ str) " ,
@@ -237,6 +246,7 @@ public function escapeMandatory(string $str, ?Position $position = null): string
237246 },
238247 ContentType::Xml => match ($ this ->state ) {
239248 self ::HtmlAttribute => "LR \\HtmlHelpers::escapeQuotes( $ str) " ,
249+ self ::HtmlAttributeExpression => "' \"' . LR \\HtmlHelpers::escapeQuotes( $ str) . ' \"' " ,
240250 self ::HtmlComment => throw new Latte \CompileException ('Using |noescape is not allowed in this context. ' , $ position ),
241251 default => $ str ,
242252 },
@@ -256,7 +266,7 @@ public function escapeContent(string $str): string
256266
257267 public function check (string $ str ): string
258268 {
259- if ($ this ->state === self ::HtmlAttribute && $ this ->subType === self ::Url) {
269+ if ($ this ->state === self ::HtmlAttributeExpression && $ this ->subType === self ::Url) {
260270 $ str = 'LR\Filters::safeUrl( ' . $ str . ') ' ;
261271 }
262272 return $ str ;
0 commit comments