| 1 | <?php |
| 2 | |
| 3 | namespace wcf\util; |
| 4 | |
| 5 | /** |
| 6 | * Contains Style-related functions. |
| 7 | * |
| 8 | * @author Marcel Werk |
| 9 | * @copyright 2001-2019 WoltLab GmbH |
| 10 | * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php> |
| 11 | */ |
| 12 | final class StyleUtil |
| 13 | { |
| 14 | /** |
| 15 | * Converts css code from LTR to RTL. |
| 16 | */ |
| 17 | public static function convertCSSToRTL(string $contents): string |
| 18 | { |
| 19 | // parse style attributes |
| 20 | // background |
| 21 | // background-position |
| 22 | $contents = \preg_replace('/background-position:\s*left/', 'wcf-background-position:left', $contents); |
| 23 | $contents = \preg_replace('/background-position:\s*right/', 'background-position:left', $contents); |
| 24 | $contents = \str_replace('wcf-background-position:left', 'background-position:right', $contents); |
| 25 | $contents = \preg_replace_callback('/background-position:\s*([\d\.]+)%/', static function ($matches) { |
| 26 | return 'background-position:' . (100.0 - $matches[1]) . '%'; |
| 27 | }, $contents); |
| 28 | |
| 29 | // background-image |
| 30 | $contents = \str_replace('-ltr', '-rtl', $contents); |
| 31 | |
| 32 | // (border, margin, padding) left / right |
| 33 | $contents = \str_replace('left:', 'wcf-left:', $contents); |
| 34 | $contents = \str_replace('right:', 'left:', $contents); |
| 35 | $contents = \str_replace('wcf-left:', 'right:', $contents); |
| 36 | |
| 37 | // border-width |
| 38 | $contents = \preg_replace( |
| 39 | '/border-width:\s*([^\s;\}]+)\s+([^\s;\}]+)\s+([^\s;\}]+)\s+([^\s;\}]+)/', |
| 40 | 'border-width:\\1 \\4 \\3 \\2', |
| 41 | $contents |
| 42 | ); |
| 43 | |
| 44 | // (border-left-width, border-right-width) |
| 45 | $contents = \str_replace('border-left-width:', 'wcf-border-left-width:', $contents); |
| 46 | $contents = \str_replace('border-right-width:', 'border-left-width:', $contents); |
| 47 | $contents = \str_replace('wcf-border-left-width:', 'border-right-width:', $contents); |
| 48 | |
| 49 | // border-style |
| 50 | $contents = \preg_replace( |
| 51 | '/border-style:\s*([^\s;\}]+)\s+([^\s;\}]+)\s+([^\s;\}]+)\s+([^\s;\}]+)/', |
| 52 | 'border-style:\\1 \\4 \\3 \\2', |
| 53 | $contents |
| 54 | ); |
| 55 | |
| 56 | // (border-left-style, border-right-style) |
| 57 | $contents = \str_replace('border-left-style:', 'wcf-border-left-style:', $contents); |
| 58 | $contents = \str_replace('border-right-style:', 'border-left-style:', $contents); |
| 59 | $contents = \str_replace('wcf-border-left-style:', 'border-right-style:', $contents); |
| 60 | |
| 61 | // (border-left-color, border-right-color) |
| 62 | $contents = \str_replace('border-left-color:', 'wcf-border-left-color:', $contents); |
| 63 | $contents = \str_replace('border-right-color:', 'border-left-color:', $contents); |
| 64 | $contents = \str_replace('wcf-border-left-color:', 'border-right-color:', $contents); |
| 65 | |
| 66 | // box-shadow |
| 67 | $contents = \preg_replace_callback( |
| 68 | '~box-shadow:\s*(?P<inset>inset)?\s*(?P<negate>-)?(?P<number>\d+)~', |
| 69 | static function ($matches) { |
| 70 | return 'box-shadow: ' . $matches['inset'] . ' ' . ($matches['negate'] ? '' : '-') . $matches['number']; |
| 71 | }, |
| 72 | $contents |
| 73 | ); |
| 74 | |
| 75 | // clear |
| 76 | $contents = \preg_replace('/clear:\s*left/', 'wcf-clear:left', $contents); |
| 77 | $contents = \preg_replace('/clear:\s*right/', 'clear:left', $contents); |
| 78 | $contents = \str_replace('wcf-clear:left', 'clear:right', $contents); |
| 79 | |
| 80 | // float |
| 81 | $contents = \preg_replace('/float:\s*left/', 'wcf-float:left', $contents); |
| 82 | $contents = \preg_replace('/float:\s*right/', 'float:left', $contents); |
| 83 | $contents = \str_replace('wcf-float:left', 'float:right', $contents); |
| 84 | |
| 85 | // margin |
| 86 | $contents = \preg_replace( |
| 87 | '/margin:\s*([^\s;\}]+)\s+([^\s;\}]+)\s+([^\s;\}]+)\s+([^\s;\}]+)/', |
| 88 | 'margin:\\1 \\4 \\3 \\2', |
| 89 | $contents |
| 90 | ); |
| 91 | |
| 92 | // padding |
| 93 | $contents = \preg_replace( |
| 94 | '/padding:\s*([^\s;\}]+)\s+([^\s;\}]+)\s+([^\s;\}]+)\s+([^\s;\}]+)/', |
| 95 | 'padding:\\1 \\4 \\3 \\2', |
| 96 | $contents |
| 97 | ); |
| 98 | |
| 99 | // text-align |
| 100 | $contents = \preg_replace('/text-align:\s*left/', 'wcf-text-align:left', $contents); |
| 101 | $contents = \preg_replace('/text-align:\s*right/', 'text-align:left', $contents); |
| 102 | $contents = \str_replace('wcf-text-align:left', 'text-align:right', $contents); |
| 103 | |
| 104 | // text-shadow |
| 105 | $contents = \preg_replace('/text-shadow:\s*(\d)/', 'text-shadow:-\\1', $contents); |
| 106 | |
| 107 | // border-radius |
| 108 | $contents = \preg_replace( |
| 109 | '/border-radius:\s*([^\s;\}]+)\s+([^\s;\}]+)\s+([^\s;\}]+)\s+([^\s;\}]+)/', |
| 110 | 'border-radius:\\2 \\1 \\4 \\3', |
| 111 | $contents |
| 112 | ); |
| 113 | $contents = \str_replace('border-top-left-radius:', 'wcf-border-top-left-radius:', $contents); |
| 114 | $contents = \str_replace('border-top-right-radius:', 'border-top-left-radius:', $contents); |
| 115 | $contents = \str_replace('wcf-border-top-left-radius:', 'border-top-right-radius:', $contents); |
| 116 | $contents = \str_replace('border-bottom-left-radius:', 'wcf-border-bottom-left-radius:', $contents); |
| 117 | $contents = \str_replace('border-bottom-right-radius:', 'border-bottom-left-radius:', $contents); |
| 118 | $contents = \str_replace('wcf-border-bottom-left-radius:', 'border-bottom-right-radius:', $contents); |
| 119 | |
| 120 | // transform: translateX |
| 121 | return \preg_replace_callback( |
| 122 | '/transform:\s*translateX\((?P<negate>-)?(?P<number>\d+)(?P<unit>[^\s\)]+)\)/', |
| 123 | static function ($matches) { |
| 124 | return 'transform: translateX(' . ($matches['negate'] ? '' : '-') . $matches['number'] . $matches['unit'] . ')'; |
| 125 | }, |
| 126 | $contents |
| 127 | ); |
| 128 | } |
| 129 | |
| 130 | /** |
| 131 | * Compresses css code. |
| 132 | */ |
| 133 | public static function compressCSS(string $string): string |
| 134 | { |
| 135 | $string = StringUtil::unifyNewlines($string); |
| 136 | |
| 137 | // remove comments |
| 138 | $string = \preg_replace('!/\*.*?\*/\r?\n?!s', '', $string); |
| 139 | // remove tabs |
| 140 | $string = \preg_replace('!\t+!', '', $string); |
| 141 | // remove line breaks |
| 142 | $string = \preg_replace('!(?<=\{|;) *\n!', '', $string); |
| 143 | $string = \preg_replace('! *\n(?=})!', '', $string); |
| 144 | // remove empty lines |
| 145 | $string = \preg_replace('~\n{2,}~s', "\n", $string); |
| 146 | |
| 147 | return StringUtil::trim($string); |
| 148 | } |
| 149 | |
| 150 | /** |
| 151 | * Forbid creation of StyleUtil objects. |
| 152 | */ |
| 153 | private function __construct() |
| 154 | { |
| 155 | // does nothing |
| 156 | } |
| 157 | } |