diff --git a/src/Latte/Runtime/Filters.php b/src/Latte/Runtime/Filters.php
index 503e3067f..90a727188 100644
--- a/src/Latte/Runtime/Filters.php
+++ b/src/Latte/Runtime/Filters.php
@@ -228,11 +228,11 @@ public static function convertHtmlToText(string $s): string
/**
* Sanitizes string for use inside href attribute.
*/
- public static function safeUrl(string|HtmlStringable $s): string
+ public static function safeUrl(string|\Stringable $s): string
{
- if ($s instanceof HtmlStringable) {
- $s = self::convertHtmlToText((string) $s);
- }
+ $s = $s instanceof HtmlStringable
+ ? self::convertHtmlToText((string) $s)
+ : (string) $s;
return preg_match('~^(?:(?:https?|ftp)://[^@]+(?:/.*)?|(?:mailto|tel|sms):.+|[/?#].*|[^:]+)$~Di', $s) ? $s : '';
}
diff --git a/tests/common/Safe.url.phpt b/tests/common/Safe.url.phpt
index 95228c091..ff7a3ebe4 100644
--- a/tests/common/Safe.url.phpt
+++ b/tests/common/Safe.url.phpt
@@ -84,3 +84,22 @@ Assert::match(
'',
$latte->renderToString('{capture $url}https://nette.org?a=1&b={=""}{/capture}'),
);
+
+Assert::match(
+ '',
+ $latte->renderToString('{capture $url}javascript:foo{/capture}'),
+);
+
+// accepts Stringable
+Assert::match(
+ '',
+ $latte->renderToString(
+ '',
+ ['url' => new class {
+ public function __toString()
+ {
+ return '';
+ }
+ }],
+ ),
+);