2024-06-20 14:10:42 +00:00
|
|
|
<?php
|
|
|
|
/**
|
|
|
|
* Class: Leaf
|
|
|
|
* Extends the Twig template engine.
|
|
|
|
*/
|
|
|
|
class Leaf extends \Twig\Extension\AbstractExtension {
|
|
|
|
/**
|
|
|
|
* Function: getFunctions
|
|
|
|
* Returns a list of operators to add to the existing list.
|
|
|
|
*/
|
|
|
|
public function getFunctions() {
|
|
|
|
return array(
|
|
|
|
# Helpers:
|
|
|
|
new \Twig\TwigFunction("url", "url"),
|
|
|
|
new \Twig\TwigFunction("self_url", "self_url"),
|
|
|
|
new \Twig\TwigFunction("authenticate", "authenticate"),
|
|
|
|
new \Twig\TwigFunction("module_enabled", "module_enabled"),
|
|
|
|
new \Twig\TwigFunction("feather_enabled", "feather_enabled"),
|
|
|
|
new \Twig\TwigFunction("password_strength", "password_strength"),
|
|
|
|
new \Twig\TwigFunction("is_url", "is_url"),
|
|
|
|
new \Twig\TwigFunction("is_email", "is_email"),
|
|
|
|
new \Twig\TwigFunction("generate_captcha", "generate_captcha"),
|
|
|
|
new \Twig\TwigFunction("javascripts", "javascripts"),
|
|
|
|
|
|
|
|
# Custom functions:
|
|
|
|
new \Twig\TwigFunction("paginate", "twig_function_paginate"),
|
|
|
|
new \Twig\TwigFunction("posted", "twig_function_posted"),
|
|
|
|
new \Twig\TwigFunction("mailto", "twig_function_mailto"),
|
|
|
|
new \Twig\TwigFunction("icon_img", "twig_function_icon_img"),
|
|
|
|
new \Twig\TwigFunction("copyright_notice", "twig_function_copyright_notice"),
|
|
|
|
new \Twig\TwigFunction("uploaded_search", "twig_function_uploaded_search"),
|
2024-09-05 17:51:48 +00:00
|
|
|
new \Twig\TwigFunction("slug_pattern", "twig_function_slug_pattern"),
|
2024-06-20 14:10:42 +00:00
|
|
|
new \Twig\TwigFunction("javascripts_nonce", "twig_function_javascripts_nonce"),
|
|
|
|
new \Twig\TwigFunction("stylesheets_nonce", "twig_function_stylesheets_nonce")
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Function: getFilters
|
|
|
|
* Returns a list of filters to add to the existing list.
|
|
|
|
*/
|
|
|
|
public function getFilters() {
|
|
|
|
return array(
|
|
|
|
# Internal:
|
|
|
|
new \Twig\TwigFilter("repeat", "str_repeat"),
|
|
|
|
|
|
|
|
# Helpers:
|
|
|
|
new \Twig\TwigFilter("camelize", "camelize"),
|
|
|
|
new \Twig\TwigFilter("decamelize", "decamelize"),
|
|
|
|
new \Twig\TwigFilter("normalize", "normalize"),
|
|
|
|
new \Twig\TwigFilter("truncate", "truncate"),
|
|
|
|
new \Twig\TwigFilter("pluralize", "pluralize"),
|
|
|
|
new \Twig\TwigFilter("depluralize", "depluralize"),
|
|
|
|
new \Twig\TwigFilter("markdown", "markdown"),
|
|
|
|
new \Twig\TwigFilter("emote", "emote"),
|
|
|
|
new \Twig\TwigFilter("oneof", "oneof"),
|
|
|
|
new \Twig\TwigFilter("fix", "fix"),
|
|
|
|
new \Twig\TwigFilter("unfix", "unfix"),
|
|
|
|
new \Twig\TwigFilter("sanitize", "sanitize"),
|
|
|
|
new \Twig\TwigFilter("sanitize_html", "sanitize_html"),
|
|
|
|
new \Twig\TwigFilter("token", "token"),
|
|
|
|
new \Twig\TwigFilter("uploaded", "uploaded"),
|
|
|
|
new \Twig\TwigFilter("gravatar", "get_gravatar"),
|
|
|
|
new \Twig\TwigFilter("add_scheme", "add_scheme"),
|
|
|
|
new \Twig\TwigFilter("lang_base", "lang_base"),
|
|
|
|
new \Twig\TwigFilter("text_direction", "text_direction"),
|
|
|
|
|
|
|
|
# Custom filters:
|
|
|
|
new \Twig\TwigFilter("translate", "twig_filter_translate"),
|
|
|
|
new \Twig\TwigFilter("translate_plural", "twig_filter_translate_plural"),
|
2024-09-05 17:51:48 +00:00
|
|
|
new \Twig\TwigFilter("translate_time", "twig_filter_translate_time"),
|
2024-06-20 14:10:42 +00:00
|
|
|
new \Twig\TwigFilter("time", "twig_filter_time"),
|
|
|
|
new \Twig\TwigFilter("dateformat", "twig_filter_date_format"),
|
|
|
|
new \Twig\TwigFilter("filesizeformat", "twig_filter_filesize_format"),
|
|
|
|
new \Twig\TwigFilter("preg_match", "twig_filter_preg_match"),
|
|
|
|
new \Twig\TwigFilter("preg_replace", "twig_filter_preg_replace"),
|
|
|
|
new \Twig\TwigFilter("contains", "twig_filter_contains"),
|
|
|
|
new \Twig\TwigFilter("inspect", "twig_filter_inspect"),
|
|
|
|
new \Twig\TwigFilter("selected", "twig_filter_selected"),
|
|
|
|
new \Twig\TwigFilter("checked", "twig_filter_checked"),
|
|
|
|
new \Twig\TwigFilter("disabled", "twig_filter_disabled"),
|
|
|
|
new \Twig\TwigFilter("download", "twig_filter_download"),
|
|
|
|
new \Twig\TwigFilter("thumbnail", "twig_filter_thumbnail")
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Function: twig_callback_missing_function
|
|
|
|
* Scans callable methods of enabled modules in search of a missing Twig function.
|
|
|
|
*
|
|
|
|
* Parameters:
|
|
|
|
* $name - The name of the missing Twig function.
|
|
|
|
*/
|
|
|
|
function twig_callback_missing_function($name): \Twig\TwigFunction|false {
|
|
|
|
foreach (Modules::$instances as $module) {
|
|
|
|
if (is_callable(array($module, "twig_function_".$name)))
|
|
|
|
return new \Twig\TwigFunction(
|
|
|
|
$name,
|
|
|
|
array($module, "twig_function_".$name)
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Function: twig_callback_missing_filter
|
|
|
|
* Scans callable methods of enabled modules in search of a missing Twig filter.
|
|
|
|
*
|
|
|
|
* Parameters:
|
|
|
|
* $name - The name of the missing Twig filter.
|
|
|
|
*/
|
|
|
|
function twig_callback_missing_filter($name): \Twig\TwigFilter|false {
|
|
|
|
foreach (Modules::$instances as $module) {
|
|
|
|
if (is_callable(array($module, "twig_filter_".$name)))
|
|
|
|
return new \Twig\TwigFilter(
|
|
|
|
$name,
|
|
|
|
array($module, "twig_filter_".$name)
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Function: twig_function_paginate
|
|
|
|
* Paginates an array of items using the Paginator class.
|
|
|
|
*
|
|
|
|
* Parameters:
|
|
|
|
* $array - The array to paginate.
|
|
|
|
* $per_page - The number of items per page.
|
|
|
|
* $name - The $_GET value for the current page.
|
|
|
|
*/
|
|
|
|
function twig_function_paginate(
|
|
|
|
$array,
|
|
|
|
$per_page = 10,
|
|
|
|
$name = "twig"
|
|
|
|
): Paginator {
|
|
|
|
# This is important for clean URL parsing in MainController.
|
|
|
|
$name = str_replace("_", "-", $name)."_page";
|
|
|
|
|
|
|
|
$count = 1;
|
|
|
|
$unique = $name;
|
|
|
|
|
|
|
|
while (in_array($unique, Paginator::$names)) {
|
|
|
|
$count++;
|
|
|
|
$unique = $name."-".$count;
|
|
|
|
}
|
|
|
|
|
|
|
|
return new Paginator($array, $per_page, $unique);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Function: twig_function_posted
|
|
|
|
* Returns a $_POST value if set, otherwise returns the fallback value.
|
|
|
|
*
|
|
|
|
* Parameters:
|
|
|
|
* $key - The key to test in the $_POST array.
|
|
|
|
* $fallback - The value to return if the $_POST value is not set.
|
|
|
|
*/
|
|
|
|
function twig_function_posted(
|
|
|
|
$index,
|
|
|
|
$fallback = ""
|
|
|
|
): string {
|
|
|
|
return isset($_POST[$index]) ?
|
|
|
|
$_POST[$index] :
|
|
|
|
$fallback ;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Function: twig_function_mailto
|
|
|
|
* Returns an obfuscated mailto: URL.
|
|
|
|
*
|
|
|
|
* Parameters:
|
|
|
|
* $email - The email address to obfuscate.
|
|
|
|
*/
|
|
|
|
function twig_function_mailto($email): ?string {
|
|
|
|
if (!is_email($email))
|
|
|
|
return null;
|
|
|
|
|
|
|
|
# "mailto:" composed in HTML entities.
|
|
|
|
$mailto = "mailto:";
|
|
|
|
|
|
|
|
# Substitute common ASCII chars for URL encodings composed in HTML entities.
|
|
|
|
$double_encode = array(
|
|
|
|
"/^-$/" => "%2D",
|
|
|
|
"/^\.$/" => "%2E",
|
|
|
|
"/^0$/" => "%30",
|
|
|
|
"/^1$/" => "%31",
|
|
|
|
"/^2$/" => "%32",
|
|
|
|
"/^3$/" => "%33",
|
|
|
|
"/^4$/" => "%34",
|
|
|
|
"/^5$/" => "%35",
|
|
|
|
"/^6$/" => "%36",
|
|
|
|
"/^7$/" => "%37",
|
|
|
|
"/^8$/" => "%38",
|
|
|
|
"/^9$/" => "%39",
|
|
|
|
"/^@$/" => "%40",
|
|
|
|
"/^A$/" => "%41",
|
|
|
|
"/^B$/" => "%42",
|
|
|
|
"/^C$/" => "%43",
|
|
|
|
"/^D$/" => "%44",
|
|
|
|
"/^E$/" => "%45",
|
|
|
|
"/^F$/" => "%46",
|
|
|
|
"/^G$/" => "%47",
|
|
|
|
"/^H$/" => "%48",
|
|
|
|
"/^I$/" => "%49",
|
|
|
|
"/^J$/" => "%4A",
|
|
|
|
"/^K$/" => "%4B",
|
|
|
|
"/^L$/" => "%4C",
|
|
|
|
"/^M$/" => "%4D",
|
|
|
|
"/^N$/" => "%4E",
|
|
|
|
"/^O$/" => "%4F",
|
|
|
|
"/^P$/" => "%50",
|
|
|
|
"/^Q$/" => "%51",
|
|
|
|
"/^R$/" => "%52",
|
|
|
|
"/^S$/" => "%53",
|
|
|
|
"/^T$/" => "%54",
|
|
|
|
"/^U$/" => "%55",
|
|
|
|
"/^V$/" => "%56",
|
|
|
|
"/^W$/" => "%57",
|
|
|
|
"/^X$/" => "%58",
|
|
|
|
"/^Y$/" => "%59",
|
|
|
|
"/^Z$/" => "%5A",
|
|
|
|
"/^_$/" => "%5F",
|
|
|
|
"/^a$/" => "%61",
|
|
|
|
"/^b$/" => "%62",
|
|
|
|
"/^c$/" => "%63",
|
|
|
|
"/^d$/" => "%64",
|
|
|
|
"/^e$/" => "%65",
|
|
|
|
"/^f$/" => "%66",
|
|
|
|
"/^g$/" => "%67",
|
|
|
|
"/^h$/" => "%68",
|
|
|
|
"/^i$/" => "%69",
|
|
|
|
"/^j$/" => "%6A",
|
|
|
|
"/^k$/" => "%6B",
|
|
|
|
"/^l$/" => "%6C",
|
|
|
|
"/^m$/" => "%6D",
|
|
|
|
"/^n$/" => "%6E",
|
|
|
|
"/^o$/" => "%6F",
|
|
|
|
"/^p$/" => "%70",
|
|
|
|
"/^q$/" => "%71",
|
|
|
|
"/^r$/" => "%72",
|
|
|
|
"/^s$/" => "%73",
|
|
|
|
"/^t$/" => "%74",
|
|
|
|
"/^u$/" => "%75",
|
|
|
|
"/^v$/" => "%76",
|
|
|
|
"/^w$/" => "%77",
|
|
|
|
"/^x$/" => "%78",
|
|
|
|
"/^y$/" => "%79",
|
|
|
|
"/^z$/" => "%7A"
|
|
|
|
);
|
|
|
|
|
|
|
|
$chars = str_split($email);
|
|
|
|
|
|
|
|
foreach ($chars as &$char)
|
|
|
|
$char = preg_replace(
|
|
|
|
array_keys($double_encode),
|
|
|
|
array_values($double_encode),
|
|
|
|
$char
|
|
|
|
);
|
|
|
|
|
|
|
|
return $mailto.implode("", $chars);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Function: twig_function_icon_img
|
|
|
|
* Returns a URL to the requested icon resource.
|
|
|
|
*
|
|
|
|
* Parameters:
|
|
|
|
* $filename - The icon filename.
|
|
|
|
* $alt_text - The alternative text for the image.
|
|
|
|
* $class - The CSS class for the link.
|
|
|
|
*/
|
|
|
|
function twig_function_icon_img(
|
|
|
|
$filename,
|
|
|
|
$alt_text = "",
|
|
|
|
$class = null
|
|
|
|
): string {
|
|
|
|
$url = Config::current()->chyrp_url.
|
|
|
|
"/admin/images/icons/".$filename;
|
|
|
|
|
|
|
|
$img = '<img src="'.fix($url, true).
|
|
|
|
'" alt="'.fix($alt_text, true);
|
|
|
|
|
|
|
|
if (isset($class) and $class !== false)
|
|
|
|
$img.= '" class="'.fix($class, true);
|
|
|
|
|
|
|
|
$img.= '">';
|
|
|
|
|
|
|
|
return $img;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Function: twig_function_copyright_notice
|
|
|
|
* Returns a copyright notice.
|
|
|
|
*
|
|
|
|
* Parameters:
|
|
|
|
* $holder - The copyright holder's name.
|
|
|
|
* $date1 - A date to use for the year.
|
|
|
|
* $date2 - End date (for a span of years).
|
|
|
|
*/
|
|
|
|
function twig_function_copyright_notice(
|
|
|
|
$holder = null,
|
|
|
|
$date1 = null,
|
|
|
|
$date2 = null,
|
|
|
|
): string {
|
|
|
|
$notice = "©";
|
|
|
|
|
|
|
|
if (isset($date1)) {
|
|
|
|
if (!is_numeric($date1))
|
|
|
|
$date1 = strtotime($date1);
|
|
|
|
|
|
|
|
$year1 = _w("Y", $date1);
|
|
|
|
$notice.= " ".$year1;
|
|
|
|
|
|
|
|
if (isset($date2)) {
|
|
|
|
if (!is_numeric($date2))
|
|
|
|
$date2 = strtotime($date2);
|
|
|
|
|
|
|
|
if ($date1 < $date2) {
|
|
|
|
$year2 = _w("Y", $date2);
|
|
|
|
|
|
|
|
if (strcmp($year1, $year2) !== 0)
|
|
|
|
$notice.= "–".$year2;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (isset($holder))
|
|
|
|
$notice.= " ".$holder;
|
|
|
|
|
|
|
|
return $notice;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Function: twig_function_uploaded_search
|
|
|
|
* Returns an array of matches, if the visitor has the "export_content" privilege.
|
|
|
|
*
|
|
|
|
* Parameters:
|
|
|
|
* $search - A search term.
|
|
|
|
* $filter - An array of valid extensions (case insensitive).
|
|
|
|
*/
|
|
|
|
function twig_function_uploaded_search(
|
|
|
|
$search = "",
|
|
|
|
$filter = array()
|
|
|
|
): array {
|
|
|
|
if (!Visitor::current()->group->can("edit_post", "edit_page", true))
|
|
|
|
return array();
|
|
|
|
|
|
|
|
return uploaded_search($search, $filter);
|
|
|
|
}
|
|
|
|
|
2024-09-05 17:51:48 +00:00
|
|
|
/**
|
|
|
|
* Function: twig_function_slug_pattern
|
|
|
|
* Returns a HTML @pattern@ attribute if strict slugs are enabled.
|
|
|
|
*/
|
|
|
|
function twig_function_slug_pattern(): string {
|
|
|
|
return SLUG_STRICT ?
|
|
|
|
' pattern="^[a-z0-9\\-]*$"' :
|
|
|
|
' pattern="^[^\\u0021-\\u002f\\u003a-\\u0040\\u005b-\\u0060\\u007b-\\u007e]*$"' ;
|
|
|
|
}
|
|
|
|
|
2024-06-20 14:10:42 +00:00
|
|
|
/**
|
|
|
|
* Function: twig_function_javascripts_nonce
|
|
|
|
* Returns a nonce value to enable inline JavaScript with a Content Security Policy.
|
|
|
|
*/
|
|
|
|
function twig_function_javascripts_nonce(): string {
|
|
|
|
$nonce = "";
|
|
|
|
return Trigger::current()->filter($nonce, "javascripts_nonce");
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Function: twig_function_stylesheets_nonce
|
|
|
|
* Returns a nonce value to enable inline stylesheets with a Content Security Policy.
|
|
|
|
*/
|
|
|
|
function twig_function_stylesheets_nonce(): string {
|
|
|
|
$nonce = "";
|
|
|
|
return Trigger::current()->filter($nonce, "stylesheets_nonce");
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Function: twig_filter_translate
|
|
|
|
* Returns a translated string.
|
|
|
|
*
|
|
|
|
* Parameters:
|
|
|
|
* $text - The string to translate.
|
|
|
|
* $domain - The translation domain to read from.
|
|
|
|
*/
|
|
|
|
function twig_filter_translate(
|
|
|
|
$string,
|
|
|
|
$domain = null
|
|
|
|
): string {
|
|
|
|
if (!isset($domain))
|
|
|
|
$domain = (ADMIN) ?
|
|
|
|
"admin" :
|
|
|
|
Theme::current()->safename ;
|
|
|
|
|
|
|
|
return __($string, $domain);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Function: twig_filter_translate_plural
|
|
|
|
* Returns a plural (or not) form of a translated string.
|
|
|
|
*
|
|
|
|
* Parameters:
|
|
|
|
* $single - Singular string.
|
|
|
|
* $plural - Pluralized string.
|
|
|
|
* $number - The number to judge by.
|
|
|
|
* $domain - The translation domain to read from.
|
|
|
|
*/
|
|
|
|
function twig_filter_translate_plural(
|
|
|
|
$single,
|
|
|
|
$plural,
|
|
|
|
$number,
|
|
|
|
$domain = null
|
|
|
|
): string {
|
|
|
|
if (!isset($domain))
|
|
|
|
$domain = (ADMIN) ?
|
|
|
|
"admin" :
|
|
|
|
Theme::current()->safename ;
|
|
|
|
|
|
|
|
return _p($single, $plural, $number, $domain);
|
|
|
|
}
|
|
|
|
|
2024-09-05 17:51:48 +00:00
|
|
|
|
2024-06-20 14:10:42 +00:00
|
|
|
/**
|
2024-09-05 17:51:48 +00:00
|
|
|
* Function: twig_filter_translate_time
|
|
|
|
* Returns a formatted and internationalized time string.
|
2024-06-20 14:10:42 +00:00
|
|
|
*
|
|
|
|
* Parameters:
|
2024-09-05 17:51:48 +00:00
|
|
|
* $timestamp - A time() value or string to be strtotime() converted.
|
|
|
|
* $format - The date()-compatible formatting.
|
2024-06-20 14:10:42 +00:00
|
|
|
*/
|
2024-09-05 17:51:48 +00:00
|
|
|
function twig_filter_translate_time(
|
2024-06-20 14:10:42 +00:00
|
|
|
$timestamp,
|
|
|
|
$format = null
|
|
|
|
): string {
|
|
|
|
if (!isset($format))
|
|
|
|
$format = (ADMIN) ? "Y-m-d" : "d F Y" ;
|
|
|
|
|
2024-09-05 17:51:48 +00:00
|
|
|
return _w($format, $timestamp);
|
2024-06-20 14:10:42 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2024-09-05 17:51:48 +00:00
|
|
|
* Function: twig_filter_time
|
|
|
|
* Returns a <time> HTML element containing an internationalized time representation.
|
2024-06-20 14:10:42 +00:00
|
|
|
*
|
|
|
|
* Parameters:
|
2024-09-05 17:51:48 +00:00
|
|
|
* $timestamp - A time() value or string to be strtotime() converted.
|
|
|
|
* $format - The date()-compatible formatting for the <time> representation.
|
|
|
|
* $convert - Perform a case conversion:
|
|
|
|
* "fold", "lower", "title", "upper", or null to retain case as-is.
|
2024-06-20 14:10:42 +00:00
|
|
|
*/
|
2024-09-05 17:51:48 +00:00
|
|
|
function twig_filter_time(
|
2024-06-20 14:10:42 +00:00
|
|
|
$timestamp,
|
2024-09-05 17:51:48 +00:00
|
|
|
$format = null,
|
|
|
|
$convert = null
|
2024-06-20 14:10:42 +00:00
|
|
|
): string {
|
|
|
|
if (!isset($format))
|
|
|
|
$format = (ADMIN) ? "Y-m-d" : "d F Y" ;
|
|
|
|
|
2024-09-05 17:51:48 +00:00
|
|
|
$string = _w($format, $timestamp);
|
|
|
|
$datetime = when("c", $timestamp);
|
|
|
|
|
|
|
|
switch ($convert) {
|
|
|
|
case "fold":
|
|
|
|
$string = mb_convert_case($string, MB_CASE_FOLD, "UTF-8");
|
|
|
|
break;
|
|
|
|
case "lower":
|
|
|
|
$string = mb_convert_case($string, MB_CASE_LOWER, "UTF-8");
|
|
|
|
break;
|
|
|
|
case "title":
|
|
|
|
$string = mb_convert_case($string, MB_CASE_TITLE, "UTF-8");
|
|
|
|
break;
|
|
|
|
case "upper":
|
|
|
|
$string = mb_convert_case($string, MB_CASE_UPPER, "UTF-8");
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
return "<time datetime=\"".$datetime."\">".$string."</time>";
|
2024-06-20 14:10:42 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2024-09-05 17:51:48 +00:00
|
|
|
* Function: twig_filter_date_format
|
2024-06-20 14:10:42 +00:00
|
|
|
* Returns date formatting for a string that isn't a regular time() value.
|
|
|
|
*
|
|
|
|
* Parameters:
|
2024-09-05 17:51:48 +00:00
|
|
|
* $timestamp - A time() value or string to be strtotime() converted.
|
|
|
|
* $formatting - The date()-compatible formatting.
|
2024-06-20 14:10:42 +00:00
|
|
|
*/
|
2024-09-05 17:51:48 +00:00
|
|
|
function twig_filter_date_format(
|
2024-06-20 14:10:42 +00:00
|
|
|
$timestamp,
|
|
|
|
$format = null
|
|
|
|
): string {
|
2024-09-05 17:51:48 +00:00
|
|
|
if (!isset($format))
|
|
|
|
$format = (ADMIN) ? "Y-m-d" : "d F Y" ;
|
|
|
|
|
|
|
|
return when($format, $timestamp);
|
2024-06-20 14:10:42 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Function: twig_filter_filesize_format
|
|
|
|
* Returns a string containing a formatted filesize value.
|
|
|
|
*
|
|
|
|
* Parameters:
|
|
|
|
* $bytes - The filesize in bytes.
|
|
|
|
*/
|
|
|
|
function twig_filter_filesize_format($bytes): string {
|
|
|
|
if (is_array($bytes))
|
|
|
|
$bytes = max($bytes);
|
|
|
|
|
|
|
|
if (is_string($bytes))
|
|
|
|
$bytes = intval($bytes);
|
|
|
|
|
|
|
|
if ($bytes >= 1000000000) {
|
|
|
|
$value = number_format($bytes / 1000000000, 1);
|
|
|
|
return _f("%s GB", $value);
|
|
|
|
}
|
|
|
|
|
|
|
|
if ($bytes >= 1048576) {
|
|
|
|
$value = number_format($bytes / 1000000, 1);
|
|
|
|
return _f("%s MB", $value);
|
|
|
|
}
|
|
|
|
|
|
|
|
$value = number_format($bytes / 1000, 1);
|
|
|
|
return _f("%s KB", $value);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Function: twig_filter_preg_match
|
|
|
|
* Try to match a string against an array of regular expressions.
|
|
|
|
*
|
|
|
|
* Parameters:
|
|
|
|
* $try - An array of regular expressions, or a single regular expression.
|
|
|
|
* $haystack - The string to test.
|
|
|
|
*/
|
|
|
|
function twig_filter_preg_match(
|
|
|
|
$haystack,
|
|
|
|
$try
|
|
|
|
): bool {
|
|
|
|
return match_any($try, $haystack);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Function: twig_filter_preg_replace
|
|
|
|
* Performs a <preg_replace> on the supplied string or array.
|
|
|
|
*
|
|
|
|
* Parameters:
|
|
|
|
* $subject - The input string.
|
|
|
|
* $pattern - The regular expression to match.
|
|
|
|
* $replacement - The replacement string.
|
|
|
|
* $limit - The maximum number of replacements.
|
|
|
|
*/
|
|
|
|
function twig_filter_preg_replace(
|
|
|
|
$subject,
|
|
|
|
$pattern,
|
|
|
|
$replacement,
|
|
|
|
$limit = -1
|
|
|
|
): ?string {
|
|
|
|
return preg_replace($pattern, $replacement, $subject, $limit);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Function: twig_filter_contains
|
|
|
|
* Does the haystack variable contain the needle variable?
|
|
|
|
*
|
|
|
|
* Parameters:
|
|
|
|
* $haystack - The variable to search within.
|
|
|
|
* $needle - The variable to search for.
|
|
|
|
*/
|
|
|
|
function twig_filter_contains(
|
|
|
|
$haystack,
|
|
|
|
$needle
|
|
|
|
): int|bool {
|
|
|
|
if (is_array($haystack))
|
|
|
|
return in_array($needle, $haystack);
|
|
|
|
|
|
|
|
if (is_string($haystack))
|
|
|
|
return substr_count($haystack, $needle);
|
|
|
|
|
|
|
|
if (is_object($haystack))
|
|
|
|
return in_array($needle, get_object_vars($haystack));
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Function: twig_filter_inspect
|
|
|
|
* Exports a variable for inspection.
|
|
|
|
*
|
|
|
|
* Parameters:
|
|
|
|
* $variable - The variable to inspect.
|
|
|
|
*/
|
|
|
|
function twig_filter_inspect($variable): string {
|
|
|
|
return '<pre class="chyrp_inspect"><code>'.
|
|
|
|
fix(var_export($variable, true)).
|
|
|
|
'</code></pre>';
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Function: twig_filter_checked
|
|
|
|
* Returns a HTML @checked@ attribute if the test evalutaes to true.
|
|
|
|
*
|
|
|
|
* Parameters:
|
|
|
|
* $test - The variable to test.
|
|
|
|
*/
|
|
|
|
function twig_filter_checked($test): string {
|
|
|
|
return ($test) ? " checked" : "" ;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Function: twig_filter_selected
|
|
|
|
* Returns a HTML @selected@ attribute if the
|
|
|
|
* test matches any of the supplied arguments.
|
|
|
|
*
|
|
|
|
* Parameters:
|
|
|
|
* $test - The variable to test.
|
|
|
|
*/
|
|
|
|
function twig_filter_selected($test): string {
|
|
|
|
$try = func_get_args();
|
|
|
|
array_shift($try);
|
|
|
|
|
|
|
|
foreach ($try as $value) {
|
|
|
|
if (
|
|
|
|
(is_array($value) and in_array($test, $value)) or
|
|
|
|
($test == $value)
|
|
|
|
)
|
|
|
|
return " selected";
|
|
|
|
}
|
|
|
|
|
|
|
|
return "";
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Function: twig_filter_disabled
|
|
|
|
* Returns a HTML @disabled@ attribute if the
|
|
|
|
* test matches any of the supplied arguments.
|
|
|
|
*
|
|
|
|
* Parameters:
|
|
|
|
* $test - The variable to test.
|
|
|
|
*/
|
|
|
|
function twig_filter_disabled($test): string {
|
|
|
|
$try = func_get_args();
|
|
|
|
array_shift($try);
|
|
|
|
|
|
|
|
foreach ($try as $value) {
|
|
|
|
if (
|
|
|
|
(is_array($value) and in_array($test, $value)) or
|
|
|
|
($test == $value)
|
|
|
|
)
|
|
|
|
return " disabled";
|
|
|
|
}
|
|
|
|
|
|
|
|
return "";
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Function: twig_filter_download
|
|
|
|
* Returns a download link for a file located in the uploads directory.
|
|
|
|
*
|
|
|
|
* Parameters:
|
|
|
|
* $filename - The uploaded filename.
|
|
|
|
*/
|
|
|
|
function twig_filter_download($filename): string {
|
|
|
|
$filepath = Config::current()->chyrp_url.
|
|
|
|
"/includes/download.php?file=".
|
|
|
|
urlencode($filename);
|
|
|
|
|
|
|
|
return fix($filepath, true);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Function: twig_filter_thumbnail
|
|
|
|
* Returns a thumbnail <img> tag for an uploaded image file,
|
|
|
|
* optionally with sizes/srcset attributes and enclosing <a> tag.
|
|
|
|
*
|
|
|
|
* Parameters:
|
|
|
|
* $filename - The uploaded filename.
|
|
|
|
* $alt_text - The alternative text for the image.
|
|
|
|
* $url - A URL, @true@ to link to the uploaded file, @false@ to disable.
|
|
|
|
* $args - An array of additional arguments to be appended as GET parameters.
|
|
|
|
* $sizes - A string, @true@ to use "100vw", @false@ to disable sizes/srcset.
|
|
|
|
* $lazy - Specify lazy-loading for this image?
|
|
|
|
*/
|
|
|
|
function twig_filter_thumbnail(
|
|
|
|
$filename,
|
|
|
|
$alt_text = "",
|
|
|
|
$url = null,
|
|
|
|
$args = array(),
|
|
|
|
$sizes = null,
|
|
|
|
$lazy = true
|
|
|
|
): string {
|
|
|
|
$filepath = Config::current()->chyrp_url.
|
|
|
|
"/includes/thumbnail.php?file=".
|
|
|
|
urlencode($filename);
|
|
|
|
|
|
|
|
$args_filtered = array();
|
|
|
|
|
|
|
|
foreach ($args as $arg) {
|
2024-09-05 17:51:48 +00:00
|
|
|
if (str_starts_with($arg, "max_width="))
|
2024-06-20 14:10:42 +00:00
|
|
|
continue;
|
|
|
|
|
2024-09-05 17:51:48 +00:00
|
|
|
if (str_starts_with($arg, "max_height="))
|
2024-06-20 14:10:42 +00:00
|
|
|
continue;
|
|
|
|
|
|
|
|
$args_filtered[] = $arg;
|
|
|
|
}
|
|
|
|
|
|
|
|
$src_args = implode("&", $args);
|
|
|
|
$set_args = implode("&", $args_filtered);
|
|
|
|
|
|
|
|
if (!empty($src_args))
|
|
|
|
$src_args = "&".$src_args;
|
|
|
|
|
|
|
|
if (!empty($set_args))
|
|
|
|
$set_args = "&".$set_args;
|
|
|
|
|
|
|
|
# Source set for responsive images.
|
|
|
|
$srcset = array(
|
|
|
|
$filepath."&max_width=2160".$set_args." 2160w",
|
|
|
|
$filepath."&max_width=1440".$set_args." 1440w",
|
|
|
|
$filepath."&max_width=1080".$set_args." 1080w",
|
|
|
|
$filepath."&max_width=720".$set_args." 720w",
|
|
|
|
$filepath."&max_width=360".$set_args." 360w",
|
|
|
|
$filepath."&max_width=180".$set_args." 180w"
|
|
|
|
);
|
|
|
|
|
|
|
|
$img = '<img src="'.fix($filepath.$src_args, true).
|
|
|
|
'" alt="'.fix($alt_text, true).
|
|
|
|
'" class="image" loading="'.($lazy ? 'lazy' : 'eager');
|
|
|
|
|
|
|
|
# Add srcset/sizes attributes? Provide @true@ or a string.
|
|
|
|
if (isset($sizes) and $sizes !== false) {
|
|
|
|
$sizes = is_string($sizes) ?
|
|
|
|
$sizes :
|
|
|
|
"100vw" ;
|
|
|
|
|
|
|
|
$img.= '" sizes="'.fix($sizes, true).
|
|
|
|
'" srcset="'.fix(implode(", ", $srcset), true);
|
|
|
|
}
|
|
|
|
|
|
|
|
$img.= '">';
|
|
|
|
|
|
|
|
# Enclose in <a> tag? Provide @true@ or a candidate URL.
|
|
|
|
if (isset($url) and $url !== false) {
|
|
|
|
$url = (is_url($url)) ?
|
|
|
|
fix($url, true) :
|
|
|
|
uploaded($filename) ;
|
|
|
|
|
|
|
|
$img = '<a href="'.$url.
|
|
|
|
'" class="image_link" aria-label="'.
|
|
|
|
__("Image source").'">'.$img.'</a>';
|
|
|
|
}
|
|
|
|
|
|
|
|
return $img;
|
|
|
|
}
|