From b72b8ffbf8154235e6b5a10daed5608957af80c0 Mon Sep 17 00:00:00 2001 From: gtbu Date: Sun, 13 Jul 2025 12:49:13 +0200 Subject: [PATCH] modernized less-vendor-prefixes and updated functions.php --- include/thirdparty/less.php/prefixes25.less | 186 ++++++++++++++++++ include/tool/functions.php | 204 +++++++++++++++----- 2 files changed, 344 insertions(+), 46 deletions(-) create mode 100644 include/thirdparty/less.php/prefixes25.less diff --git a/include/thirdparty/less.php/prefixes25.less b/include/thirdparty/less.php/prefixes25.less new file mode 100644 index 0000000..e1f3cb8 --- /dev/null +++ b/include/thirdparty/less.php/prefixes25.less @@ -0,0 +1,186 @@ +// Universal Prefixes for LESS - 2025 Edition +// +// This file provides a manual alternative to Autoprefixer. +// It uses parts of https://github.com/JoelSutherland/LESS-Prefixer MIT license and of older Bootstrap 3.2 - vendor prefixes +// It has been updated to remove obsolete prefixes and focuses on those still relevant +// for modern browser support, primarily `-webkit-` for Safari and iOS. +// It's recommended to always include the standard, unprefixed property last. [7] +// +//--------------------------------------------------- +// TABLE OF CONTENTS +//--------------------------------------------------- +// .animation() +// .appearance() +// .backface-visibility() +// .box-shadow() - (No prefixes needed) +// .box-sizing() - (No prefixes needed) +// .columns() +// .filter() +// .flex-block() / .flex-inline() & Flexbox properties +// .hyphens() +// .keyframes() +// .linear-gradient() +// .placeholder() +// .transform() & related properties +// .transition() & related properties +// .user-select() +//--------------------------------------------------- + +// Animation +// `-webkit-` is still useful for full compatibility in some scenarios. [5] +.animation(@animation) { + -webkit-animation: @animation; + animation: @animation; +} + +.animation-name(@name) { + -webkit-animation-name: @name; + animation-name: @name; +} + +.animation-duration(@duration) { + -webkit-animation-duration: @duration; + animation-duration: @duration; +} + +.animation-timing-function(@timing-function) { + -webkit-animation-timing-function: @timing-function; + animation-timing-function: @timing-function; +} + +// Appearance +// Used to style form controls. `-webkit-` and `-moz-` are still required. +.appearance(@appearance) { + -webkit-appearance: @appearance; + -moz-appearance: @appearance; + appearance: @appearance; +} + +// Backface Visibility +// Prevents flickering in 3D transforms. `-webkit-` is the primary prefix needed. +.backface-visibility(@visibility) { + -webkit-backface-visibility: @visibility; + backface-visibility: @visibility; +} + +// Box Shadow +// Prefixes are no longer needed for modern browsers. [11] +.box-shadow(@shadow) { + box-shadow: @shadow; +} + +// Box Sizing +// Fully supported in modern browsers without prefixes. +.box-sizing(@boxmodel) { + box-sizing: @boxmodel; +} + +// CSS Columns +// `-webkit-` and `-moz-` can still be useful for full compatibility. [2] +.content-columns(@column-count; @column-gap: 20px) { + -webkit-column-count: @column-count; + -moz-column-count: @column-count; + column-count: @column-count; + -webkit-column-gap: @column-gap; + -moz-column-gap: @column-gap; + column-gap: @column-gap; +} + +// Filter +// `-webkit-` is still necessary for some filter functions in Safari. +.filter(@filter) { + -webkit-filter: @filter; + filter: @filter; +} + +// Flexbox +// The core properties are well-supported, but `-webkit-` can help with older Safari versions. +.flex-block() { + display: -webkit-flex; + display: flex; +} + +.flex-inline() { + display: -webkit-inline-flex; + display: inline-flex; +} + +.flex-direction(@direction: row) { + -webkit-flex-direction: @direction; + flex-direction: @direction; +} + +.justify-content(@justify) { + -webkit-justify-content: @justify; + justify-content: @justify; +} + +.align-items(@align) { + -webkit-align-items: @align; + align-items: @align; +} + +.flex-grow(@grow: 1) { + -webkit-flex-grow: @grow; + flex-grow: @grow; +} + +// Hyphens +// Useful for controlling text wrapping. +.hyphens(@mode: auto) { + -webkit-hyphens: @mode; + -moz-hyphens: @mode; + hyphens: @mode; +} + +// Keyframes +// Requires `-webkit-` prefix for full compatibility. +.keyframes(@name; @args) { + @-webkit-keyframes @name { @args(); } + @keyframes @name { @args(); } +} + +// Gradients +// Standard syntax is well-supported, but `-webkit-` can be a fallback. +.linear-gradient(@direction; @start-color; @end-color) { + background-color: @end-color; // Fallback + background-image: -webkit-linear-gradient(@direction, @start-color, @end-color); + background-image: linear-gradient(@direction, @start-color, @end-color); +} + +// Placeholder Text +// The nested selector approach remains the standard way to style placeholders. +.placeholder(@color: #aaa) { + &::-webkit-input-placeholder { color: @color; } + &::-moz-placeholder { color: @color; opacity: 1; } // Firefox 19+ + &:-ms-input-placeholder { color: @color; } // IE 10+ + &::-ms-input-placeholder { color: @color; } // Edge + &::placeholder { color: @color; } +} + +// Transformations +// `-webkit-` is the only prefix with some remaining relevance for transforms. +.transform(@transform) { + -webkit-transform: @transform; + transform: @transform; +} + +.transform-origin(@origin) { + -webkit-transform-origin: @origin; + transform-origin: @origin; +} + +// Transitions +// `-webkit-` is still useful for ensuring smooth transitions across all browsers. +.transition(@transition) { + -webkit-transition: @transition; + transition: @transition; +} + +// User Select +// Prevents text selection. Prefixes are still necessary for full support. +.user-select(@select) { + -webkit-user-select: @select; + -moz-user-select: @select; + user-select: @select; +} \ No newline at end of file diff --git a/include/tool/functions.php b/include/tool/functions.php index 4788e8c..7db67db 100644 --- a/include/tool/functions.php +++ b/include/tool/functions.php @@ -1,101 +1,213 @@ mb_substr_replace($s, $r, $st, $l, $encoding), + $str, + $repl, + $start, + $length + ); + } + if (is_array($repl) || is_array($start) || is_array($length)) { + trigger_error('mb_substr_replace(): Passing an array for replacement, start, or length is not supported when the main string is not an array.', E_USER_WARNING); + return false; + } + $str_len = mb_strlen($str, $encoding); + if ($start < 0) { + $start = max(0, $str_len + $start); + } else { + $start = min($start, $str_len); + } + if ($length === null) { + $length = $str_len - $start; + } elseif ($length < 0) { + $length = max(0, $str_len - $start + $length); + } else { + $length = min($length, $str_len - $start); + } + $before = mb_substr($str, 0, $start, $encoding); + $after = mb_substr($str, $start + $length, null, $encoding); + return $before . $repl . $after; } -if( !function_exists('mb_str_replace') ){ - function mb_str_replace($search, $replace, $subject, &$count = 0){ +/** + * Multibyte-safe str_replace() equivalent. * + * @param string|array $search + * @param string|array $replace + * @param string|array $subject + * @param int $count (by reference) Count of replacements made + * @param string|null $encoding Optional character encoding + * @return string|array + */ +if (!function_exists('mb_str_replace')) { + + function mb_str_replace($search, $replace, $subject, &$count = 0, ?string $encoding = null) { + if (is_array($subject)) { + foreach ($subject as $key => $value) { + $subject[$key] = mb_str_replace($search, $replace, $value, $count, $encoding); + } + return $subject; + } - // Call mb_str_replace for each subject in array, recursively - if( is_array($subject) ){ - foreach ($subject as $key => $value) { - $subject[$key] = mb_str_replace($search, $replace, $value, $count); - } - return $subject; - } + $encoding = $encoding ?? mb_internal_encoding(); + $subject = (string) $subject; + $searches = is_array($search) ? array_values($search) : [$search]; + $replacements = is_array($replace) ? array_values($replace) : [$replace]; + $replacements = array_pad($replacements, count($searches), ''); - // Normalize $search and $replace so they are both arrays of the same length - $searches = is_array($search) ? array_values($search) : array($search); - $replacements = is_array($replace) ? array_values($replace) : array($replace); - $replacements = array_pad($replacements, count($searches), ''); - foreach( $searches as $key => $search ){ - $parts = mb_split(preg_quote($search), $subject); - $count += count($parts) - 1; - $subject = implode($replacements[$key], $parts); - } - return $subject; - } + foreach ($searches as $key => $searchTerm) { + $searchTerm = (string) $searchTerm; + + if ($searchTerm === '') { + trigger_error('mb_str_replace(): Empty search string is not supported', E_USER_WARNING); + continue; + } + + $replaceWith = (string) $replacements[$key]; + $offset = 0; + while (($pos = mb_strpos($subject, $searchTerm, $offset, $encoding)) !== false) { + $subject = mb_substr($subject, 0, $pos, $encoding) + . $replaceWith + . mb_substr($subject, $pos + mb_strlen($searchTerm, $encoding), null, $encoding); + + $offset = $pos + mb_strlen($replaceWith, $encoding); + $count++; + } + } + return $subject; + } } -if( !function_exists('mb_explode') ){ - function mb_explode(){ - $args = func_get_args(); - $args[0] = preg_quote($args[0]); - return call_user_func_array('mb_split',$args); - } +if (!function_exists('mb_explode')) { + /** + * A multi-byte safe version of the native PHP explode() function, + * @param string $delimiter The boundary string. + * @param string $string The input string. + * @param int $limit + * @return array Returns an array of strings. + * @throws ValueError if the delimiter is an empty string, mimicking PHP 8's explode(). + */ + function mb_explode(string $delimiter, string $string, int $limit = PHP_INT_MAX): array + { + if ($delimiter === '') { + throw new ValueError('mb_explode(): Argument #1 ($delimiter) must not be empty'); + } + + if (mb_strpos($string, $delimiter) === false) { + return [$string]; + } + + if ($limit === 0) { + $limit = 1; + } + + $result = []; + $current_string = $string; + $delimiter_length = mb_strlen($delimiter); + + if ($limit > 0) { + + while (count($result) < $limit - 1) { + $pos = mb_strpos($current_string, $delimiter); + if ($pos === false) { + break; + } + $result[] = mb_substr($current_string, 0, $pos); + $current_string = mb_substr($current_string, $pos + $delimiter_length); + } + + $result[] = $current_string; + return $result; + } + + while (($pos = mb_strpos($current_string, $delimiter)) !== false) { + $result[] = mb_substr($current_string, 0, $pos); + $current_string = mb_substr($current_string, $pos + $delimiter_length); + } + $result[] = $current_string; + + return array_slice($result, 0, $limit); + } } +/* https://www.php.net/manual/de/function.gzopen.php */ if( !function_exists('gzopen') && function_exists('gzopen64') ){ function gzopen( $filename, $mode, $use_include_path = 0 ){ return gzopen64( $filename, $mode, $use_include_path ); } } +/* If not, the function is defined as an empty function */ if( !function_exists('gpSettingsOverride') ){ function gpSettingsOverride(){} }