From 0c1fa050f3021eaf7055627a732ddbaab20fd2f8 Mon Sep 17 00:00:00 2001 From: ale <ale@incal.net> Date: Sat, 7 May 2022 12:02:25 +0100 Subject: [PATCH] Add a plugin to sanitize custom CSS data --- csstidy/class.csstidy-ctype.php | 53 ++ csstidy/class.csstidy-optimise.php | 1007 +++++++++++++++++++++ csstidy/class.csstidy-print.php | 432 +++++++++ csstidy/class.csstidy.php | 1307 ++++++++++++++++++++++++++++ csstidy/cssparse-rtl.css | 146 ++++ csstidy/cssparse-rtl.min.css | 1 + csstidy/cssparse.css | 118 +++ csstidy/cssparse.min.css | 1 + csstidy/cssparsed-rtl.css | 29 + csstidy/cssparsed-rtl.min.css | 1 + csstidy/cssparsed.css | 29 + csstidy/cssparsed.min.css | 1 + csstidy/data-wp.inc.php | 102 +++ csstidy/data.inc.php | 777 +++++++++++++++++ csstidy/lang.inc.php | 303 +++++++ csstidy/wordpress-standard.tpl | 10 + custom-css.php | 73 ++ 17 files changed, 4390 insertions(+) create mode 100644 csstidy/class.csstidy-ctype.php create mode 100644 csstidy/class.csstidy-optimise.php create mode 100644 csstidy/class.csstidy-print.php create mode 100644 csstidy/class.csstidy.php create mode 100644 csstidy/cssparse-rtl.css create mode 100644 csstidy/cssparse-rtl.min.css create mode 100644 csstidy/cssparse.css create mode 100644 csstidy/cssparse.min.css create mode 100644 csstidy/cssparsed-rtl.css create mode 100644 csstidy/cssparsed-rtl.min.css create mode 100644 csstidy/cssparsed.css create mode 100644 csstidy/cssparsed.min.css create mode 100644 csstidy/data-wp.inc.php create mode 100644 csstidy/data.inc.php create mode 100644 csstidy/lang.inc.php create mode 100644 csstidy/wordpress-standard.tpl create mode 100644 custom-css.php diff --git a/csstidy/class.csstidy-ctype.php b/csstidy/class.csstidy-ctype.php new file mode 100644 index 0000000..a94b39b --- /dev/null +++ b/csstidy/class.csstidy-ctype.php @@ -0,0 +1,53 @@ +<?php +/** + * CSSTidy - CSS Parser and Optimiser + * + * CSS ctype functions + * Defines some functions that can be not defined. + * + * This file is part of CSSTidy. + * + * CSSTidy is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * CSSTidy is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with CSSTidy; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + * @license https://opensource.org/licenses/gpl-license.php GNU Public License + * @package csstidy + * @author Nikolay Matsievsky (speed at webo dot name) 2009-2010 + * @version 1.0 + */ + +if ( ! function_exists( 'ctype_space' ) ) { + + /** + * Check for whitespace character(s). + * + * @param string $text - the text. + */ + function ctype_space( $text ) { + return ! preg_match( "/[^\s\r\n\t\f]/", $text ); + } +} + +if ( ! function_exists( 'ctype_alpha' ) ) { + + /** + * Check for alphabetic character(s) + * + * @param string $text - the text. + */ + function ctype_alpha( $text ) { + return preg_match( '/[a-zA-Z]/', $text ); + } +} + diff --git a/csstidy/class.csstidy-optimise.php b/csstidy/class.csstidy-optimise.php new file mode 100644 index 0000000..0889b01 --- /dev/null +++ b/csstidy/class.csstidy-optimise.php @@ -0,0 +1,1007 @@ +<?php // phpcs:ignore WordPress.Files.FileName.InvalidClassFileName +/** + * CSSTidy - CSS Parser and Optimiser + * + * CSS Optimising Class + * This class optimises CSS data generated by csstidy. + * + * Copyright 2005, 2006, 2007 Florian Schmitz + * + * This file is part of CSSTidy. + * + * CSSTidy is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1 of the License, or + * (at your option) any later version. + * + * CSSTidy is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + * + * @license https://opensource.org/licenses/lgpl-license.php GNU Lesser General Public License + * @package csstidy + * @author Florian Schmitz (floele at gmail dot com) 2005-2007 + * @author Brett Zamir (brettz9 at yahoo dot com) 2007 + * @author Nikolay Matsievsky (speed at webo dot name) 2009-2010 + */ + +/** + * CSS Optimising Class + * + * This class optimises CSS data generated by csstidy. + * + * @package csstidy + * @author Florian Schmitz (floele at gmail dot com) 2005-2006 + * @version 1.0 + */ +class csstidy_optimise { // phpcs:ignore + /** + * Constructor + * + * @param array $css contains the class csstidy. + * @access private + * @version 1.0 + */ + public function __construct( &$css ) { + $this->parser = & $css; + $this->css = & $css->css; + $this->sub_value = & $css->sub_value; + $this->at = & $css->at; + $this->selector = & $css->selector; + $this->property = & $css->property; + $this->value = & $css->value; + } + + /** + * Call constructor function. + * + * @param object $css - the CSS. + */ + public function csstidy_optimise( &$css ) { + $this->__construct( $css ); + } + + /** + * Optimises $css after parsing + * + * @access public + * @version 1.0 + */ + public function postparse() { + if ( $this->parser->get_cfg( 'preserve_css' ) ) { + return; + } + + if ( $this->parser->get_cfg( 'merge_selectors' ) === 2 ) { + foreach ( $this->css as $medium => $value ) { + $this->merge_selectors( $this->css[ $medium ] ); + } + } + + if ( $this->parser->get_cfg( 'discard_invalid_selectors' ) ) { + foreach ( $this->css as $medium => $value ) { + $this->discard_invalid_selectors( $this->css[ $medium ] ); + } + } + + if ( $this->parser->get_cfg( 'optimise_shorthands' ) > 0 ) { + foreach ( $this->css as $medium => $value ) { + foreach ( $value as $selector => $value1 ) { + $this->css[ $medium ][ $selector ] = self::merge_4value_shorthands( $this->css[ $medium ][ $selector ] ); + + if ( $this->parser->get_cfg( 'optimise_shorthands' ) < 2 ) { + continue; + } + + $this->css[ $medium ][ $selector ] = self::merge_font( $this->css[ $medium ][ $selector ] ); + + if ( $this->parser->get_cfg( 'optimise_shorthands' ) < 3 ) { + continue; + } + + $this->css[ $medium ][ $selector ] = self::merge_bg( $this->css[ $medium ][ $selector ] ); + if ( empty( $this->css[ $medium ][ $selector ] ) ) { + unset( $this->css[ $medium ][ $selector ] ); + } + } + } + } + } + + /** + * Optimises values + * + * @access public + * @version 1.0 + */ + public function value() { + $shorthands = & $GLOBALS['csstidy']['shorthands']; + + // optimise shorthand properties. + if ( isset( $shorthands[ $this->property ] ) ) { + $temp = self::shorthand( $this->value ); // FIXME - move. + if ( $temp !== $this->value ) { + $this->parser->log( 'Optimised shorthand notation (' . $this->property . '): Changed "' . $this->value . '" to "' . $temp . '"', 'Information' ); + } + $this->value = $temp; + } + + // Remove whitespace at ! important. + if ( $this->value !== $this->compress_important( $this->value ) ) { + $this->parser->log( 'Optimised !important', 'Information' ); + } + } + + /** + * Optimises shorthands + * + * @access public + * @version 1.0 + */ + public function shorthands() { + $shorthands = & $GLOBALS['csstidy']['shorthands']; + + if ( ! $this->parser->get_cfg( 'optimise_shorthands' ) || $this->parser->get_cfg( 'preserve_css' ) ) { + return; + } + + if ( $this->property === 'font' && $this->parser->get_cfg( 'optimise_shorthands' ) > 1 ) { + $this->css[ $this->at ][ $this->selector ]['font'] = ''; + $this->parser->merge_css_blocks( $this->at, $this->selector, self::dissolve_short_font( $this->value ) ); + } + if ( $this->property === 'background' && $this->parser->get_cfg( 'optimise_shorthands' ) > 2 ) { + $this->css[ $this->at ][ $this->selector ]['background'] = ''; + $this->parser->merge_css_blocks( $this->at, $this->selector, self::dissolve_short_bg( $this->value ) ); + } + if ( isset( $shorthands[ $this->property ] ) ) { + $this->parser->merge_css_blocks( $this->at, $this->selector, self::dissolve_4value_shorthands( $this->property, $this->value ) ); + if ( is_array( $shorthands[ $this->property ] ) ) { + $this->css[ $this->at ][ $this->selector ][ $this->property ] = ''; + } + } + } + + /** + * Optimises a sub-value + * + * @access public + * @version 1.0 + */ + public function subvalue() { + $replace_colors = & $GLOBALS['csstidy']['replace_colors']; + + $this->sub_value = trim( $this->sub_value ); + if ( $this->sub_value === '' ) { + return; + } + + $important = ''; + if ( csstidy::is_important( $this->sub_value ) ) { + $important = '!important'; + } + $this->sub_value = csstidy::gvw_important( $this->sub_value ); + + // Compress font-weight. + if ( $this->property === 'font-weight' && $this->parser->get_cfg( 'compress_font-weight' ) ) { + if ( $this->sub_value === 'bold' ) { + $this->sub_value = '700'; + $this->parser->log( 'Optimised font-weight: Changed "bold" to "700"', 'Information' ); + } elseif ( $this->sub_value === 'normal' ) { + $this->sub_value = '400'; + $this->parser->log( 'Optimised font-weight: Changed "normal" to "400"', 'Information' ); + } + } + + $temp = $this->compress_numbers( $this->sub_value ); + if ( strcasecmp( $temp, $this->sub_value ) !== 0 ) { + if ( strlen( $temp ) > strlen( $this->sub_value ) ) { + $this->parser->log( 'Fixed invalid number: Changed "' . $this->sub_value . '" to "' . $temp . '"', 'Warning' ); + } else { + $this->parser->log( 'Optimised number: Changed "' . $this->sub_value . '" to "' . $temp . '"', 'Information' ); + } + $this->sub_value = $temp; + } + if ( $this->parser->get_cfg( 'compress_colors' ) ) { + $temp = $this->cut_color( $this->sub_value ); + if ( $temp !== $this->sub_value ) { + if ( isset( $replace_colors[ $this->sub_value ] ) ) { + $this->parser->log( 'Fixed invalid color name: Changed "' . $this->sub_value . '" to "' . $temp . '"', 'Warning' ); + } else { + $this->parser->log( 'Optimised color: Changed "' . $this->sub_value . '" to "' . $temp . '"', 'Information' ); + } + $this->sub_value = $temp; + } + } + $this->sub_value .= $important; + } + + /** + * Compresses shorthand values. Example: margin:1px 1px 1px 1px -> margin:1px + * + * @param string $value - the value. + * @access public + * @return string + * @version 1.0 + */ + public static function shorthand( $value ) { + $important = ''; + if ( csstidy::is_important( $value ) ) { + $values = csstidy::gvw_important( $value ); + $important = '!important'; + } else { + $values = $value; + } + + $values = explode( ' ', $values ); + switch ( count( $values ) ) { + case 4: + if ( $values[0] === $values[1] && $values[0] === $values[2] && $values[0] === $values[3] ) { + return $values[0] . $important; + } elseif ( $values[1] === $values[3] && $values[0] === $values[2] ) { + return $values[0] . ' ' . $values[1] . $important; + } elseif ( $values[1] === $values[3] ) { + return $values[0] . ' ' . $values[1] . ' ' . $values[2] . $important; + } + break; + + case 3: + if ( $values[0] === $values[1] && $values[0] === $values[2] ) { + return $values[0] . $important; + } elseif ( $values[0] === $values[2] ) { + return $values[0] . ' ' . $values[1] . $important; + } + break; + + case 2: + if ( $values[0] === $values[1] ) { + return $values[0] . $important; + } + break; + } + + return $value; + } + + /** + * Removes unnecessary whitespace in ! important + * + * @param string $string - the string. + * @return string + * @access public + * @version 1.1 + */ + public function compress_important( &$string ) { + if ( csstidy::is_important( $string ) ) { + $string = csstidy::gvw_important( $string ) . ' !important'; } + return $string; + } + + /** + * Color compression function. Converts all rgb() values to #-values and uses the short-form if possible. Also replaces 4 color names by #-values. + * + * @param string $color - the color. + * @return string + * @version 1.1 + */ + public function cut_color( $color ) { + $replace_colors = & $GLOBALS['csstidy']['replace_colors']; + + // an example: rgb(0,0,0) -> #000000 (or #000 in this case later). + if ( strtolower( substr( $color, 0, 4 ) ) === 'rgb(' ) { + $color_tmp = substr( $color, 4, strlen( $color ) - 5 ); + $color_tmp = explode( ',', $color_tmp ); + for ( $i = 0, $l = count( $color_tmp ); $i < $l; $i++ ) { + $color_tmp[ $i ] = trim( $color_tmp[ $i ] ); + if ( substr( $color_tmp[ $i ], -1 ) === '%' ) { + $color_tmp[ $i ] = round( ( 255 * $color_tmp[ $i ] ) / 100 ); + } + if ( $color_tmp[ $i ] > 255 ) { + $color_tmp[ $i ] = 255; + } + } + $color = '#'; + for ( $i = 0; $i < 3; $i++ ) { + if ( $color_tmp[ $i ] < 16 ) { + $color .= '0' . dechex( $color_tmp[ $i ] ); + } else { + $color .= dechex( $color_tmp[ $i ] ); + } + } + } + + // Fix bad color names. + if ( isset( $replace_colors[ strtolower( $color ) ] ) ) { + $color = $replace_colors[ strtolower( $color ) ]; + } + + // #aabbcc -> #abc + if ( strlen( $color ) === 7 ) { + $color_temp = strtolower( $color ); + if ( $color_temp[0] === '#' && $color_temp[1] === $color_temp[2] && $color_temp[3] === $color_temp[4] && $color_temp[5] === $color_temp[6] ) { + $color = '#' . $color[1] . $color[3] . $color[5]; + } + } + + switch ( strtolower( $color ) ) { + /* color name -> hex code */ + case 'black': + return '#000'; + case 'fuchsia': + return '#f0f'; + case 'white': + return '#fff'; + case 'yellow': + return '#ff0'; + + /* hex code -> color name */ + case '#800000': + return 'maroon'; + case '#ffa500': + return 'orange'; + case '#808000': + return 'olive'; + case '#800080': + return 'purple'; + case '#008000': + return 'green'; + case '#000080': + return 'navy'; + case '#008080': + return 'teal'; + case '#c0c0c0': + return 'silver'; + case '#808080': + return 'gray'; + case '#f00': + return 'red'; + } + + return $color; + } + + /** + * Compresses numbers (ie. 1.0 becomes 1 or 1.100 becomes 1.1 ) + * + * @param string $subvalue - the subvalue. + * @return string + * @version 1.2 + */ + public function compress_numbers( $subvalue ) { + $unit_values = & $GLOBALS['csstidy']['unit_values']; + $color_values = & $GLOBALS['csstidy']['color_values']; + + // for font:1em/1em sans-serif...;. + if ( $this->property === 'font' ) { + $temp = explode( '/', $subvalue ); + } else { + $temp = array( $subvalue ); + } + + for ( $l = 0, $m = count( $temp ); $l < $m; $l++ ) { + // if we are not dealing with a number at this point, do not optimise anything. + $number = $this->analyse_css_number( $temp[ $l ] ); + if ( $number === false ) { + return $subvalue; + } + + // Fix bad colors. + if ( in_array( $this->property, $color_values, true ) ) { + if ( strlen( $temp[ $l ] ) === 3 || strlen( $temp[ $l ] ) === 6 ) { + $temp[ $l ] = '#' . $temp[ $l ]; + } else { + $temp[ $l ] = '0'; + } + continue; + } + + if ( abs( $number[0] ) > 0 ) { + if ( $number[1] === '' && in_array( $this->property, $unit_values, true ) ) { + $number[1] = 'px'; + } + } else { + $number[1] = ''; + } + + $temp[ $l ] = $number[0] . $number[1]; + } + + return ( ( count( $temp ) > 1 ) ? $temp[0] . '/' . $temp[1] : $temp[0] ); + } + + /** + * Checks if a given string is a CSS valid number. If it is, + * an array containing the value and unit is returned + * + * @param string $string - the string we're checking. + * @return array ('unit' if unit is found or '' if no unit exists, number value) or false if no number + */ + public function analyse_css_number( $string ) { + // most simple checks first + if ( $string === '' || ctype_alpha( $string[0] ) ) { + return false; + } + + $units = & $GLOBALS['csstidy']['units']; + $return = array( 0, '' ); + + $return[0] = (float) $string; + if ( abs( $return[0] ) > 0 && abs( $return[0] ) < 1 ) { + // Removes the initial `0` from a decimal number, e.g., `0.7 => .7` or `-0.666 => -.666`. + if ( ! $this->parser->get_cfg( 'preserve_leading_zeros' ) ) { + if ( $return[0] < 0 ) { + $return[0] = '-' . ltrim( substr( $return[0], 1 ), '0' ); + } else { + $return[0] = ltrim( $return[0], '0' ); + } + } + } + + // Look for unit and split from value if exists + foreach ( $units as $unit ) { + $expect_unit_at = strlen( $string ) - strlen( $unit ); + $unit_in_string = stristr( $string, $unit ); + if ( ! $unit_in_string ) { // mb_strpos() fails with "false" + continue; + } + $actual_position = strpos( $string, $unit_in_string ); + if ( $expect_unit_at === $actual_position ) { + $return[1] = $unit; + $string = substr( $string, 0, - strlen( $unit ) ); + break; + } + } + if ( ! is_numeric( $string ) ) { + return false; + } + return $return; + } + + /** + * Merges selectors with same properties. Example: a{color:red} b{color:red} -> a,b{color:red} + * Very basic and has at least one bug. Hopefully there is a replacement soon. + * + * @param array $array - the selector array. + * @access public + * @version 1.2 + */ + public function merge_selectors( &$array ) { + $css = $array; + foreach ( $css as $key => $value ) { + if ( ! isset( $css[ $key ] ) ) { + continue; + } + $newsel = ''; + + // Check if properties also exist in another selector. + $keys = array(); + // PHP bug (?) without $css = $array; here. + foreach ( $css as $selector => $vali ) { + if ( $selector === $key ) { + continue; + } + + if ( $css[ $key ] === $vali ) { + $keys[] = $selector; + } + } + + if ( ! empty( $keys ) ) { + $newsel = $key; + unset( $css[ $key ] ); + foreach ( $keys as $selector ) { + unset( $css[ $selector ] ); + $newsel .= ',' . $selector; + } + $css[ $newsel ] = $value; + } + } + $array = $css; + } + + /** + * Removes invalid selectors and their corresponding rule-sets as + * defined by 4.1.7 in REC-CSS2. This is a very rudimentary check + * and should be replaced by a full-blown parsing algorithm or + * regular expression + * + * @version 1.4 + * + * @param array $array - selector array. + */ + public function discard_invalid_selectors( &$array ) { + foreach ( $array as $selector => $decls ) { + $ok = true; + $selectors = array_map( 'trim', explode( ',', $selector ) ); + foreach ( $selectors as $s ) { + $simple_selectors = preg_split( '/\s*[+>~\s]\s*/', $s ); + foreach ( $simple_selectors as $ss ) { + if ( $ss === '' ) { + $ok = false; + } + // could also check $ss for internal structure, but that probably would be too slow. + } + } + if ( ! $ok ) { + unset( $array[ $selector ] ); + } + } + } + + /** + * Dissolves properties like padding:10px 10px 10px to padding-top:10px;padding-bottom:10px;... + * + * @param string $property - the property. + * @param string $value - the value. + * @return array + * @version 1.0 + * @see merge_4value_shorthands() + */ + public static function dissolve_4value_shorthands( $property, $value ) { + $shorthands = & $GLOBALS['csstidy']['shorthands']; + if ( ! is_array( $shorthands[ $property ] ) ) { + $return = array(); + $return[ $property ] = $value; + return $return; + } + + $important = ''; + if ( csstidy::is_important( $value ) ) { + $value = csstidy::gvw_important( $value ); + $important = '!important'; + } + $values = explode( ' ', $value ); + + $return = array(); + if ( count( $values ) === 4 ) { + for ( $i = 0; $i < 4; $i++ ) { + $return[ $shorthands[ $property ][ $i ] ] = $values[ $i ] . $important; + } + } elseif ( count( $values ) === 3 ) { + $return[ $shorthands[ $property ][0] ] = $values[0] . $important; + $return[ $shorthands[ $property ][1] ] = $values[1] . $important; + $return[ $shorthands[ $property ][3] ] = $values[1] . $important; + $return[ $shorthands[ $property ][2] ] = $values[2] . $important; + } elseif ( count( $values ) === 2 ) { + for ( $i = 0; $i < 4; $i++ ) { + $return[ $shorthands[ $property ][ $i ] ] = ( ( $i % 2 !== 0 ) ) ? $values[1] . $important : $values[0] . $important; + } + } else { + for ( $i = 0; $i < 4; $i++ ) { + $return[ $shorthands[ $property ][ $i ] ] = $values[0] . $important; + } + } + + return $return; + } + + /** + * Explodes a string as explode() does, however, not if $sep is escaped or within a string. + * + * @param string $sep - seperator. + * @param string $string - the string. + * @return array + * @version 1.0 + */ + public static function explode_ws( $sep, $string ) { + $status = 'st'; + $to = ''; + + $output = array(); + $num = 0; + for ( $i = 0, $len = strlen( $string ); $i < $len; $i++ ) { + switch ( $status ) { + case 'st': + if ( $string[ $i ] === $sep && ! csstidy::escaped( $string, $i ) ) { + ++$num; + } elseif ( $string[ $i ] === '"' || $string[ $i ] === '\'' || $string[ $i ] === '(' && ! csstidy::escaped( $string, $i ) ) { + $status = 'str'; + $to = ( $string[ $i ] === '(' ) ? ')' : $string[ $i ]; + ( isset( $output[ $num ] ) ) ? $output[ $num ] .= $string[ $i ] : $output[ $num ] = $string[ $i ]; + } else { + ( isset( $output[ $num ] ) ) ? $output[ $num ] .= $string[ $i ] : $output[ $num ] = $string[ $i ]; + } + break; + + case 'str': + if ( $string[ $i ] === $to && ! csstidy::escaped( $string, $i ) ) { + $status = 'st'; + } + ( isset( $output[ $num ] ) ) ? $output[ $num ] .= $string[ $i ] : $output[ $num ] = $string[ $i ]; + break; + } + } + + if ( isset( $output[0] ) ) { + return $output; + } else { + return array( $output ); + } + } + + /** + * Merges Shorthand properties again, the opposite of dissolve_4value_shorthands() + * + * @param array $array - the property array. + * @return array + * @version 1.2 + * @see dissolve_4value_shorthands() + */ + public static function merge_4value_shorthands( $array ) { + $return = $array; + $shorthands = & $GLOBALS['csstidy']['shorthands']; + + foreach ( $shorthands as $key => $value ) { + if ( isset( $array[ $value[0] ] ) && isset( $array[ $value[1] ] ) + && isset( $array[ $value[2] ] ) && isset( $array[ $value[3] ] ) && $value !== 0 ) { + $return[ $key ] = ''; + + $important = ''; + for ( $i = 0; $i < 4; $i++ ) { + $val = $array[ $value[ $i ] ]; + if ( csstidy::is_important( $val ) ) { + $important = '!important'; + $return[ $key ] .= csstidy::gvw_important( $val ) . ' '; + } else { + $return[ $key ] .= $val . ' '; + } + unset( $return[ $value[ $i ] ] ); + } + $return[ $key ] = self::shorthand( trim( $return[ $key ] . $important ) ); + } + } + return $return; + } + + /** + * Dissolve background property + * + * @param string $str_value - the string value. + * @return array + * @version 1.0 + * @see merge_bg() + * @todo full CSS 3 compliance + */ + public static function dissolve_short_bg( $str_value ) { + $have = array(); + // don't try to explose background gradient ! + if ( stripos( $str_value, 'gradient(' ) !== false ) { + return array( 'background' => $str_value ); + } + + $background_prop_default = & $GLOBALS['csstidy']['background_prop_default']; + $repeat = array( 'repeat', 'repeat-x', 'repeat-y', 'no-repeat', 'space' ); + $attachment = array( 'scroll', 'fixed', 'local' ); + $clip = array( 'border', 'padding' ); + $origin = array( 'border', 'padding', 'content' ); + $pos = array( 'top', 'center', 'bottom', 'left', 'right' ); + $important = ''; + $return = array( + 'background-image' => null, + 'background-size' => null, + 'background-repeat' => null, + 'background-position' => null, + 'background-attachment' => null, + 'background-clip' => null, + 'background-origin' => null, + 'background-color' => null, + ); + + if ( csstidy::is_important( $str_value ) ) { + $important = ' !important'; + $str_value = csstidy::gvw_important( $str_value ); + } + + $str_value = self::explode_ws( ',', $str_value ); + for ( $i = 0, $l = count( $str_value ); $i < $l; $i++ ) { + $have['clip'] = false; + $have['pos'] = false; + $have['color'] = false; + $have['bg'] = false; + + if ( is_array( $str_value[ $i ] ) ) { + $str_value[ $i ] = $str_value[ $i ][0]; + } + $str_value[ $i ] = self::explode_ws( ' ', trim( $str_value[ $i ] ) ); + + for ( $j = 0, $k = count( $str_value[ $i ] ); $j < $k; $j++ ) { + if ( $have['bg'] === false && ( substr( $str_value[ $i ][ $j ], 0, 4 ) === 'url(' || $str_value[ $i ][ $j ] === 'none' ) ) { + $return['background-image'] .= $str_value[ $i ][ $j ] . ','; + $have['bg'] = true; + } elseif ( in_array( $str_value[ $i ][ $j ], $repeat, true ) ) { + $return['background-repeat'] .= $str_value[ $i ][ $j ] . ','; + } elseif ( in_array( $str_value[ $i ][ $j ], $attachment, true ) ) { + $return['background-attachment'] .= $str_value[ $i ][ $j ] . ','; + } elseif ( in_array( $str_value[ $i ][ $j ], $clip, true ) && ! $have['clip'] ) { + $return['background-clip'] .= $str_value[ $i ][ $j ] . ','; + $have['clip'] = true; + } elseif ( in_array( $str_value[ $i ][ $j ], $origin, true ) ) { + $return['background-origin'] .= $str_value[ $i ][ $j ] . ','; + } elseif ( $str_value[ $i ][ $j ][0] === '(' ) { + $return['background-size'] .= substr( $str_value[ $i ][ $j ], 1, -1 ) . ','; + } elseif ( in_array( $str_value[ $i ][ $j ], $pos, true ) || is_numeric( $str_value[ $i ][ $j ][0] ) || $str_value[ $i ][ $j ][0] === null || $str_value[ $i ][ $j ][0] === '-' || $str_value[ $i ][ $j ][0] === '.' ) { + $return['background-position'] .= $str_value[ $i ][ $j ]; + if ( ! $have['pos'] ) { + $return['background-position'] .= ' '; + } else { + $return['background-position'] .= ','; + } + $have['pos'] = true; + } elseif ( ! $have['color'] ) { + $return['background-color'] .= $str_value[ $i ][ $j ] . ','; + $have['color'] = true; + } + } + } + + foreach ( $background_prop_default as $bg_prop => $default_value ) { + if ( $return[ $bg_prop ] !== null ) { + $return[ $bg_prop ] = substr( $return[ $bg_prop ], 0, -1 ) . $important; + } else { + $return[ $bg_prop ] = $default_value . $important; + } + } + return $return; + } + + /** + * Merges all background properties + * + * @param array $input_css - inputted CSS. + * @return array + * @version 1.0 + * @see dissolve_short_bg() + * @todo full CSS 3 compliance + */ + public static function merge_bg( $input_css ) { + $background_prop_default = & $GLOBALS['csstidy']['background_prop_default']; + // Max number of background images. CSS3 not yet fully implemented. + $number_of_values = @max( count( self::explode_ws( ',', $input_css['background-image'] ) ), count( self::explode_ws( ',', $input_css['background-color'] ) ), 1 ); // phpcs:ignore WordPress.PHP.NoSilencedErrors.Discouraged + // Array with background images to check if BG image exists. + $bg_img_array = @self::explode_ws( ',', csstidy::gvw_important( $input_css['background-image'] ) ); // phpcs:ignore WordPress.PHP.NoSilencedErrors.Discouraged + $new_bg_value = ''; + $important = ''; + + // if background properties is here and not empty, don't try anything. + if ( isset( $input_css['background'] ) && $input_css['background'] ) { + return $input_css; + } + + for ( $i = 0; $i < $number_of_values; $i++ ) { + foreach ( $background_prop_default as $bg_property => $default_value ) { + // Skip if property does not exist + if ( ! isset( $input_css[ $bg_property ] ) ) { + continue; + } + + $cur_value = $input_css[ $bg_property ]; + // skip all optimisation if gradient() somewhere. + if ( stripos( $cur_value, 'gradient(' ) !== false ) { + return $input_css; + } + + // Skip some properties if there is no background image. + if ( ( ! isset( $bg_img_array[ $i ] ) || $bg_img_array[ $i ] === 'none' ) + && ( $bg_property === 'background-size' || $bg_property === 'background-position' + || $bg_property === 'background-attachment' || $bg_property === 'background-repeat' ) ) { + continue; + } + + // Remove !important. + if ( csstidy::is_important( $cur_value ) ) { + $important = ' !important'; + $cur_value = csstidy::gvw_important( $cur_value ); + } + + // Do not add default values. + if ( $cur_value === $default_value ) { + continue; + } + + $temp = self::explode_ws( ',', $cur_value ); + + if ( isset( $temp[ $i ] ) ) { + if ( $bg_property === 'background-size' ) { + $new_bg_value .= '(' . $temp[ $i ] . ') '; + } else { + $new_bg_value .= $temp[ $i ] . ' '; + } + } + } + + $new_bg_value = trim( $new_bg_value ); + if ( $i !== $number_of_values - 1 ) { + $new_bg_value .= ','; + } + } + + // Delete all background-properties. + foreach ( $background_prop_default as $bg_property => $default_value ) { + unset( $input_css[ $bg_property ] ); + } + + // Add new background property. + if ( $new_bg_value !== '' ) { + $input_css['background'] = $new_bg_value . $important; + } elseif ( isset( $input_css['background'] ) ) { + $input_css['background'] = 'none'; + } + + return $input_css; + } + + /** + * Dissolve font property + * + * @param string $str_value - the string value. + * @return array + * @version 1.3 + * @see merge_font() + */ + public static function dissolve_short_font( $str_value ) { + $have = array(); + $font_prop_default = & $GLOBALS['csstidy']['font_prop_default']; + $font_weight = array( 'normal', 'bold', 'bolder', 'lighter', '100', '200', '300', '400', '500', '600', '700', '800', '900' ); + $font_variant = array( 'normal', 'small-caps' ); + $font_style = array( 'normal', 'italic', 'oblique' ); + $important = ''; + $return = array( + 'font-style' => null, + 'font-variant' => null, + 'font-weight' => null, + 'font-size' => null, + 'line-height' => null, + 'font-family' => null, + ); + + if ( csstidy::is_important( $str_value ) ) { + $important = '!important'; + $str_value = csstidy::gvw_important( $str_value ); + } + + $have['style'] = false; + $have['variant'] = false; + $have['weight'] = false; + $have['size'] = false; + // Detects if font-family consists of several words w/o quotes. + $multiwords = false; + + // Workaround with multiple font-family. + $str_value = self::explode_ws( ',', trim( $str_value ) ); + + $str_value[0] = self::explode_ws( ' ', trim( $str_value[0] ) ); + + for ( $j = 0, $k = count( $str_value[0] ); $j < $k; $j++ ) { + if ( $have['weight'] === false && in_array( $str_value[0][ $j ], $font_weight, true ) ) { + $return['font-weight'] = $str_value[0][ $j ]; + $have['weight'] = true; + } elseif ( $have['variant'] === false && in_array( $str_value[0][ $j ], $font_variant, true ) ) { + $return['font-variant'] = $str_value[0][ $j ]; + $have['variant'] = true; + } elseif ( $have['style'] === false && in_array( $str_value[0][ $j ], $font_style, true ) ) { + $return['font-style'] = $str_value[0][ $j ]; + $have['style'] = true; + } elseif ( $have['size'] === false && ( is_numeric( $str_value[0][ $j ][0] ) || $str_value[0][ $j ][0] === null || $str_value[0][ $j ][0] === '.' ) ) { + $size = self::explode_ws( '/', trim( $str_value[0][ $j ] ) ); + $return['font-size'] = $size[0]; + if ( isset( $size[1] ) ) { + $return['line-height'] = $size[1]; + } else { + $return['line-height'] = ''; // don't add 'normal' ! + } + $have['size'] = true; + } else { + if ( isset( $return['font-family'] ) ) { + $return['font-family'] .= ' ' . $str_value[0][ $j ]; + $multiwords = true; + } else { + $return['font-family'] = $str_value[0][ $j ]; + } + } + } + // add quotes if we have several qords in font-family. + if ( $multiwords !== false ) { + $return['font-family'] = '"' . $return['font-family'] . '"'; + } + $i = 1; + while ( isset( $str_value[ $i ] ) ) { + $return['font-family'] .= ',' . trim( $str_value[ $i ] ); + $i++; + } + + // Fix for 100 and more font-size. + if ( $have['size'] === false && isset( $return['font-weight'] ) && + is_numeric( $return['font-weight'][0] ) + ) { + $return['font-size'] = $return['font-weight']; + unset( $return['font-weight'] ); + } + + foreach ( $font_prop_default as $font_prop => $default_value ) { + if ( $return[ $font_prop ] !== null ) { + $return[ $font_prop ] = $return[ $font_prop ] . $important; + } else { + $return[ $font_prop ] = $default_value . $important; + } + } + return $return; + } + + /** + * Merges all fonts properties + * + * @param array $input_css - input CSS. + * @return array + * @version 1.3 + * @see dissolve_short_font() + */ + public static function merge_font( $input_css ) { + $font_prop_default = & $GLOBALS['csstidy']['font_prop_default']; + $new_font_value = ''; + $important = ''; + // Skip if not font-family and font-size set. + if ( isset( $input_css['font-family'] ) && isset( $input_css['font-size'] ) ) { + // fix several words in font-family - add quotes. + if ( isset( $input_css['font-family'] ) ) { + $families = explode( ',', $input_css['font-family'] ); + $result_families = array(); + foreach ( $families as $family ) { + $family = trim( $family ); + $len = strlen( $family ); + if ( strpos( $family, ' ' ) && + ! ( ( $family[0] === '"' && $family[ $len - 1 ] === '"' ) || + ( $family[0] === "'" && $family[ $len - 1 ] === "'" ) ) ) { + $family = '"' . $family . '"'; + } + $result_families[] = $family; + } + $input_css['font-family'] = implode( ',', $result_families ); + } + foreach ( $font_prop_default as $font_property => $default_value ) { + + // Skip if property does not exist. + if ( ! isset( $input_css[ $font_property ] ) ) { + continue; + } + + $cur_value = $input_css[ $font_property ]; + + // Skip if default value is used. + if ( $cur_value === $default_value ) { + continue; + } + + // Remove !important. + if ( csstidy::is_important( $cur_value ) ) { + $important = '!important'; + $cur_value = csstidy::gvw_important( $cur_value ); + } + + $new_font_value .= $cur_value; + // Add delimiter. + $new_font_value .= ( $font_property === 'font-size' && + isset( $input_css['line-height'] ) ) ? '/' : ' '; + } + + $new_font_value = trim( $new_font_value ); + + // Delete all font-properties. + foreach ( $font_prop_default as $font_property => $default_value ) { + if ( $font_property !== 'font' || ! $new_font_value ) { + unset( $input_css[ $font_property ] ); + } + } + + // Add new font property. + if ( $new_font_value !== '' ) { + $input_css['font'] = $new_font_value . $important; + } + } + + return $input_css; + } + +} diff --git a/csstidy/class.csstidy-print.php b/csstidy/class.csstidy-print.php new file mode 100644 index 0000000..5ce9de5 --- /dev/null +++ b/csstidy/class.csstidy-print.php @@ -0,0 +1,432 @@ +<?php // phpcs:ignore WordPress.Files.FileName.InvalidClassFileName +/** + * CSSTidy - CSS Parser and Optimiser + * + * CSS Printing class + * This class prints CSS data generated by csstidy. + * + * Copyright 2005, 2006, 2007 Florian Schmitz + * + * This file is part of CSSTidy. + * + * CSSTidy is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1 of the License, or + * (at your option) any later version. + * + * CSSTidy is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + * + * @license https://opensource.org/licenses/lgpl-license.php GNU Lesser General Public License + * @package csstidy + * @author Florian Schmitz (floele at gmail dot com) 2005-2007 + * @author Brett Zamir (brettz9 at yahoo dot com) 2007 + * @author Cedric Morin (cedric at yterium dot com) 2010 + */ + +/** + * CSS Printing class + * + * This class prints CSS data generated by csstidy. + * + * @package csstidy + * @author Florian Schmitz (floele at gmail dot com) 2005-2006 + * @version 1.0.1 + */ +class csstidy_print { // phpcs:ignore + + /** + * Saves the input CSS string + * + * @var string + * @access private + */ + public $input_css = ''; + /** + * Saves the formatted CSS string + * + * @var string + * @access public + */ + public $output_css = ''; + /** + * Saves the formatted CSS string (plain text) + * + * @var string + * @access public + */ + public $output_css_plain = ''; + + /** + * Constructor + * + * @param array $css contains the class csstidy. + * @access private + * @version 1.0 + */ + public function __construct( &$css ) { + $this->parser = & $css; + $this->css = & $css->css; + $this->template = & $css->template; + $this->tokens = & $css->tokens; + $this->charset = & $css->charset; + $this->import = & $css->import; + $this->namespace = & $css->namespace; + } + + /** + * Call constructor function. + * + * @param object $css - the CSS we're working with. + */ + public function csstidy_print( &$css ) { + $this->__construct( $css ); + } + + /** + * Resets output_css and output_css_plain (new css code) + * + * @access private + * @version 1.0 + */ + public function _reset() { // phpcs:ignore PSR2.Methods.MethodDeclaration.Underscore + $this->output_css = ''; + $this->output_css_plain = ''; + } + + /** + * Returns the CSS code as plain text + * + * @param string $default_media default @media to add to selectors without any @media. + * @return string + * @access public + * @version 1.0 + */ + public function plain( $default_media = '' ) { + $this->_print( true, $default_media ); + return $this->output_css_plain; + } + + /** + * Returns the formatted CSS code + * + * @param string $default_media default @media to add to selectors without any @media. + * @return string + * @access public + * @version 1.0 + */ + public function formatted( $default_media = '' ) { + $this->_print( false, $default_media ); + return $this->output_css; + } + + /** + * Returns the formatted CSS code to make a complete webpage + * + * @param string $doctype shorthand for the document type. + * @param bool $externalcss indicates whether styles to be attached internally or as an external stylesheet. + * @param string $title title to be added in the head of the document. + * @param string $lang two-letter language code to be added to the output. + * @return string + * @access public + * @version 1.4 + */ + public function formatted_page( $doctype = 'xhtml1.1', $externalcss = true, $title = '', $lang = 'en' ) { + switch ( $doctype ) { + case 'xhtml1.0strict': + $doctype_output = '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" + "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">'; + break; + case 'xhtml1.1': + default: + $doctype_output = '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" + "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">'; + break; + } + $cssparsed = ''; + $output = ''; + $this->output_css_plain = & $output; + + $output .= $doctype_output . "\n" . '<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="' . $lang . '"'; + $output .= ( $doctype === 'xhtml1.1' ) ? '>' : ' lang="' . $lang . '">'; + $output .= "\n<head>\n <title>$title</title>"; + + if ( $externalcss ) { + $output .= "\n <style type=\"text/css\">\n"; + $cssparsed = file_get_contents( 'cssparsed.css' ); // phpcs:ignore WordPress.WP.AlternativeFunctions.file_get_contents_file_get_contents + $output .= $cssparsed; // Adds an invisible BOM or something, but not in css_optimised.php + $output .= "\n</style>"; + } else { + $output .= "\n" . ' <link rel="stylesheet" type="text/css" href="cssparsed.css" />'; // phpcs:ignore WordPress.WP.EnqueuedResources.NonEnqueuedStylesheet + // } + } + $output .= "\n</head>\n<body><code id=\"copytext\">"; + $output .= $this->formatted(); + $output .= '</code>' . "\n" . '</body></html>'; + return $this->output_css_plain; + } + + /** + * Returns the formatted CSS Code and saves it into $this->output_css and $this->output_css_plain + * + * @param bool $plain plain text or not. + * @param string $default_media default @media to add to selectors without any @media. + * @access private + * @version 2.0 + */ + public function _print( $plain = false, $default_media = '' ) { // phpcs:ignore PSR2.Methods.MethodDeclaration.Underscore -- print is a reserved word anyway. + if ( $this->output_css && $this->output_css_plain ) { + return; + } + + $output = ''; + if ( ! $this->parser->get_cfg( 'preserve_css' ) ) { + $this->convert_raw_css( $default_media ); + } + + $template = & $this->template; + + if ( $plain ) { + $template = array_map( 'strip_tags', $template ); + } + + if ( $this->parser->get_cfg( 'timestamp' ) ) { + array_unshift( $this->tokens, array( COMMENT, ' CSSTidy ' . $this->parser->version . ': ' . gmdate( 'r' ) . ' ' ) ); + } + + if ( ! empty( $this->charset ) ) { + $output .= $template[0] . '@charset ' . $template[5] . $this->charset . $template[6]; + } + + if ( ! empty( $this->import ) ) { + for ( $i = 0, $size = count( $this->import ); $i < $size; $i++ ) { + $import_components = explode( ' ', $this->import[ $i ] ); + if ( substr( $import_components[0], 0, 4 ) === 'url(' && substr( $import_components[0], -1, 1 ) === ')' ) { + $import_components[0] = '\'' . trim( substr( $import_components[0], 4, -1 ), "'\"" ) . '\''; + $this->import[ $i ] = implode( ' ', $import_components ); + $this->parser->log( 'Optimised @import : Removed "url("', 'Information' ); + } + $output .= $template[0] . '@import ' . $template[5] . $this->import[ $i ] . $template[6]; + } + } + if ( ! empty( $this->namespace ) ) { + if ( substr( $this->namespace, 0, 4 ) === 'url(' && substr( $this->namespace, -1, 1 ) === ')' ) { + $this->namespace = '\'' . substr( $this->namespace, 4, -1 ) . '\''; + $this->parser->log( 'Optimised @namespace : Removed "url("', 'Information' ); + } + $output .= $template[0] . '@namespace ' . $template[5] . $this->namespace . $template[6]; + } + + $output .= $template[13]; + $in_at_out = ''; + $out = & $output; + + foreach ( $this->tokens as $key => $token ) { + switch ( $token[0] ) { + case AT_START: + $out .= $template[0] . $this->htmlsp( $token[1], $plain ) . $template[1]; + $out = & $in_at_out; + break; + + case SEL_START: + if ( $this->parser->get_cfg( 'lowercase_s' ) ) { + $token[1] = strtolower( $token[1] ); + } + $out .= ( $token[1][0] !== '@' ) ? $template[2] . $this->htmlsp( $token[1], $plain ) : $template[0] . $this->htmlsp( $token[1], $plain ); + $out .= $template[3]; + break; + + case PROPERTY: + if ( $this->parser->get_cfg( 'case_properties' ) === 2 ) { + $token[1] = strtoupper( $token[1] ); + } elseif ( $this->parser->get_cfg( 'case_properties' ) === 1 ) { + $token[1] = strtolower( $token[1] ); + } + $out .= $template[4] . $this->htmlsp( $token[1], $plain ) . ':' . $template[5]; + break; + + case VALUE: + $out .= $this->htmlsp( $token[1], $plain ); + if ( $this->seeknocomment( $key, 1 ) === SEL_END && $this->parser->get_cfg( 'remove_last_;' ) ) { + $out .= str_replace( ';', '', $template[6] ); + } else { + $out .= $template[6]; + } + break; + + case SEL_END: + $out .= $template[7]; + if ( $this->seeknocomment( $key, 1 ) !== AT_END ) { + $out .= $template[8]; + } + break; + + case AT_END: + $out = & $output; + $out .= $template[10] . str_replace( "\n", "\n" . $template[10], $in_at_out ); + $in_at_out = ''; + $out .= $template[9]; + break; + + case COMMENT: + $out .= $template[11] . '/*' . $this->htmlsp( $token[1], $plain ) . '*/' . $template[12]; + break; + } + } + + $output = trim( $output ); + + if ( ! $plain ) { + $this->output_css = $output; + $this->_print( true ); + } else { + // If using spaces in the template, don't want these to appear in the plain output + $this->output_css_plain = str_replace( ' ', '', $output ); + } + } + + /** + * Gets the next token type which is $move away from $key, excluding comments + * + * @param integer $key current position. + * @param integer $move move this far. + * @return mixed a token type + * @access private + * @version 1.0 + */ + public function seeknocomment( $key, $move ) { + $go = ( $move > 0 ) ? 1 : -1; + for ( $i = $key + 1; abs( $key - $i ) - 1 < abs( $move ); $i += $go ) { // phpcs:ignore Generic.CodeAnalysis.ForLoopWithTestFunctionCall.NotAllowed + if ( ! isset( $this->tokens[ $i ] ) ) { + return; + } + if ( $this->tokens[ $i ][0] === COMMENT ) { + ++$move; + continue; + } + return $this->tokens[ $i ][0]; + } + } + + /** + * Converts $this->css array to a raw array ($this->tokens) + * + * @param string $default_media default @media to add to selectors without any @media. + * @access private + * @version 1.0 + */ + public function convert_raw_css( $default_media = '' ) { + $this->tokens = array(); + + foreach ( $this->css as $medium => $val ) { + if ( $this->parser->get_cfg( 'sort_selectors' ) ) { + ksort( $val ); + } + if ( (int) $medium < DEFAULT_AT ) { + $this->parser->_add_token( AT_START, $medium, true ); + } elseif ( $default_media ) { + $this->parser->_add_token( AT_START, $default_media, true ); + } + + foreach ( $val as $selector => $vali ) { + if ( $this->parser->get_cfg( 'sort_properties' ) ) { + ksort( $vali ); + } + $this->parser->_add_token( SEL_START, $selector, true ); + + foreach ( $vali as $property => $valj ) { + $this->parser->_add_token( PROPERTY, $property, true ); + $this->parser->_add_token( VALUE, $valj, true ); + } + + $this->parser->_add_token( SEL_END, $selector, true ); + } + + if ( (int) $medium < DEFAULT_AT ) { + $this->parser->_add_token( AT_END, $medium, true ); + } elseif ( $default_media ) { + $this->parser->_add_token( AT_END, $default_media, true ); + } + } + } + + /** + * Same as htmlspecialchars, only that chars are not replaced if $plain !== true. This makes print_code() cleaner. + * + * @param string $string - the string we're converting. + * @param bool $plain - plain text or not. + * @return string + * @see csstidy_print::_print() + * @access private + * @version 1.0 + */ + public function htmlsp( $string, $plain ) { + if ( ! $plain ) { + return htmlspecialchars( $string, ENT_QUOTES, 'utf-8' ); + } + return $string; + } + + /** + * Get compression ratio + * + * @access public + * @return float + * @version 1.2 + */ + public function get_ratio() { + if ( ! $this->output_css_plain ) { + $this->formatted(); + } + return round( ( strlen( $this->input_css ) - strlen( $this->output_css_plain ) ) / strlen( $this->input_css ), 3 ) * 100; + } + + /** + * Get difference between the old and new code in bytes and prints the code if necessary. + * + * @access public + * @return string + * @version 1.1 + */ + public function get_diff() { + if ( ! $this->output_css_plain ) { + $this->formatted(); + } + + $diff = strlen( $this->output_css_plain ) - strlen( $this->input_css ); + + if ( $diff > 0 ) { + return '+' . $diff; + } elseif ( $diff === 0 ) { + return '+-' . $diff; + } + + return $diff; + } + + /** + * Get the size of either input or output CSS in KB + * + * @param string $loc default is "output". + * @access public + * @return integer + * @version 1.0 + */ + public function size( $loc = 'output' ) { + if ( $loc === 'output' && ! $this->output_css ) { + $this->formatted(); + } + + if ( $loc === 'input' ) { + return ( strlen( $this->input_css ) / 1000 ); + } else { + return ( strlen( $this->output_css_plain ) / 1000 ); + } + } + +} diff --git a/csstidy/class.csstidy.php b/csstidy/class.csstidy.php new file mode 100644 index 0000000..76c5af5 --- /dev/null +++ b/csstidy/class.csstidy.php @@ -0,0 +1,1307 @@ +<?php // phpcs:ignore WordPress.Files.FileName.InvalidClassFileName +/** + * CSSTidy - CSS Parser and Optimiser + * + * CSS Parser class + * + * Copyright 2005, 2006, 2007 Florian Schmitz + * + * This file is part of CSSTidy. + * + * CSSTidy is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1 of the License, or + * (at your option) any later version. + * + * CSSTidy is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + * + * @license https://opensource.org/licenses/lgpl-license.php GNU Lesser General Public License + * @package csstidy + * @author Florian Schmitz (floele at gmail dot com) 2005-2007 + * @author Brett Zamir (brettz9 at yahoo dot com) 2007 + * @author Nikolay Matsievsky (speed at webo dot name) 2009-2010 + * @author Cedric Morin (cedric at yterium dot com) 2010 + */ + +// phpcs:disable WordPress.PHP.NoSilencedErrors.Discouraged + +/** + * Defines ctype functions if required + * + * @version 1.0 + */ +require_once __DIR__ . '/class.csstidy-ctype.php'; + +/** + * Various CSS data needed for correct optimisations etc. + * + * @version 1.3 + */ +require __DIR__ . '/data.inc.php'; + +/** + * Contains a class for printing CSS code + * + * @version 1.0 + */ +require __DIR__ . '/class.csstidy-print.php'; + +/** + * Contains a class for optimising CSS code + * + * @version 1.0 + */ +require __DIR__ . '/class.csstidy-optimise.php'; + +/** + * CSS Parser class + + * This class represents a CSS parser which reads CSS code and saves it in an array. + * In opposite to most other CSS parsers, it does not use regular expressions and + * thus has full CSS2 support and a higher reliability. + * Additional to that it applies some optimisations and fixes to the CSS code. + * An online version should be available here: https://cdburnerxp.se/cssparse/css_optimiser.php + * + * @package csstidy + * @author Florian Schmitz (floele at gmail dot com) 2005-2006 + * @version 1.3.1 + */ +class csstidy { // phpcs:ignore + + /** + * Saves the parsed CSS. This array is empty if preserve_css is on. + * + * @var array + * @access public + */ + public $css = array(); + /** + * Saves the parsed CSS (raw) + * + * @var array + * @access private + */ + public $tokens = array(); + /** + * Printer class + * + * @see csstidy_print + * @var object + * @access public + */ + public $print; + /** + * Optimiser class + * + * @see csstidy_optimise + * @var object + * @access private + */ + public $optimise; + /** + * Saves the CSS charset (@charset) + * + * @var string + * @access private + */ + public $charset = ''; + /** + * Saves all @import URLs + * + * @var array + * @access private + */ + public $import = array(); + /** + * Saves the namespace + * + * @var string + * @access private + */ + public $namespace = ''; + /** + * Contains the version of csstidy + * + * @var string + * @access private + */ + public $version = '1.3'; + /** + * Stores the settings + * + * @var array + * @access private + */ + public $settings = array(); + /** + * Saves the parser-status. + * + * Possible values: + * - is = in selector + * - ip = in property + * - iv = in value + * - instr = in string (started at " or ' or ( ) + * - ic = in comment (ignore everything) + * - at = in @-block + * + * @var string + * @access private + */ + public $status = 'is'; + /** + * Saves the current at rule (@media) + * + * @var string + * @access private + */ + public $at = ''; + /** + * Saves the current selector + * + * @var string + * @access private + */ + public $selector = ''; + /** + * Saves the current property + * + * @var string + * @access private + */ + public $property = ''; + /** + * Saves the position of , in selectors + * + * @var array + * @access private + */ + public $sel_separate = array(); + /** + * Saves the current value + * + * @var string + * @access private + */ + public $value = ''; + /** + * Saves the current sub-value + * + * Example for a subvalue: + * background:url(foo.png) red no-repeat; + * "url(foo.png)", "red", and "no-repeat" are subvalues, + * separated by whitespace + * + * @var string + * @access private + */ + public $sub_value = ''; + /** + * Array which saves all subvalues for a property. + * + * @var array + * @see sub_value + * @access private + */ + public $sub_value_arr = array(); + /** + * Saves the stack of characters that opened the current strings + * + * @var array + * @access private + */ + public $str_char = array(); + /** + * Current strings. + * + * @var array + * @access private + */ + public $cur_string = array(); + /** + * Status from which the parser switched to ic or instr + * + * @var array + * @access private + */ + public $from = array(); + /** + /** + * =true if in invalid at-rule + * + * @var bool + * @access private + */ + public $invalid_at = false; + /** + * =true if something has been added to the current selector + * + * @var bool + * @access private + */ + public $added = false; + /** + * Array which saves the message log + * + * @var array + * @access private + */ + public $log = array(); + /** + * Saves the line number + * + * @var integer + * @access private + */ + public $line = 1; + /** + * Marks if we need to leave quotes for a string + * + * @var array + * @access private + */ + public $quoted_string = array(); + + /** + * List of tokens + * + * @var string + */ + public $tokens_list = ''; + + /** + * Loads standard template and sets default settings. + * + * @access private + * @version 1.3 + */ + public function __construct() { + $this->settings['remove_bslash'] = true; + $this->settings['compress_colors'] = true; + $this->settings['compress_font-weight'] = true; + $this->settings['lowercase_s'] = false; + + /* + 1 common shorthands optimization + 2 + font property optimization + 3 + background property optimization + */ + $this->settings['optimise_shorthands'] = 1; + $this->settings['remove_last_;'] = true; + /* rewrite all properties with low case, better for later gzip OK, safe*/ + $this->settings['case_properties'] = 1; + + /* + * sort properties in alpabetic order, better for later gzip + * but can cause trouble in case of overiding same propertie or using hack + */ + $this->settings['sort_properties'] = false; + + /* + 1, 3, 5, etc -- enable sorting selectors inside @media: a{}b{}c{} + 2, 5, 8, etc -- enable sorting selectors inside one CSS declaration: a,b,c{} + preserve order by default cause it can break functionnality + */ + $this->settings['sort_selectors'] = 0; + /* is dangeroues to be used: CSS is broken sometimes */ + $this->settings['merge_selectors'] = 0; + /* preserve or not browser hacks */ + $this->settings['discard_invalid_selectors'] = false; + $this->settings['discard_invalid_properties'] = false; + $this->settings['css_level'] = 'CSS2.1'; + $this->settings['preserve_css'] = false; + $this->settings['timestamp'] = false; + $this->settings['template'] = ''; // say that propertie exist. + $this->set_cfg( 'template', 'default' ); // call load_template. + /* Tells csstidy_optimise to keep leading zeros on decimal numbers, e.g., 0.7 */ + $this->settings['preserve_leading_zeros'] = false; + $this->optimise = new csstidy_optimise( $this ); + + $this->tokens_list = & $GLOBALS['csstidy']['tokens']; + } + + /** + * Call the construct function. + */ + public function csstidy() { + $this->__construct(); + } + + /** + * Get the value of a setting. + * + * @param string $setting - the settings. + * @access public + * @return mixed + * @version 1.0 + */ + public function get_cfg( $setting ) { + if ( isset( $this->settings[ $setting ] ) ) { + return $this->settings[ $setting ]; + } + return false; + } + + /** + * Load a template + * + * @param string $template used by set_cfg to load a template via a configuration setting. + * @access private + * @version 1.4 + */ + public function _load_template( $template ) { // phpcs:ignore PSR2.Methods.MethodDeclaration.Underscore + switch ( $template ) { + case 'default': + $this->load_template( 'default' ); + break; + + case 'highest': + $this->load_template( 'highest_compression' ); + break; + + case 'high': + $this->load_template( 'high_compression' ); + break; + + case 'low': + $this->load_template( 'low_compression' ); + break; + + default: + $this->load_template( $template ); + break; + } + } + + /** + * Set the value of a setting. + * + * @param string $setting - the setting. + * @param mixed $value - the value we're setting. + * @access public + * @return bool + * @version 1.0 + */ + public function set_cfg( $setting, $value = null ) { + if ( is_array( $setting ) && null === $value ) { + foreach ( $setting as $setprop => $setval ) { + $this->settings[ $setprop ] = $setval; + } + if ( array_key_exists( 'template', $setting ) ) { + $this->_load_template( $this->settings['template'] ); + } + return true; + } elseif ( isset( $this->settings[ $setting ] ) && '' !== $value ) { + $this->settings[ $setting ] = $value; + if ( 'template' === $setting ) { + $this->_load_template( $this->settings['template'] ); + } + return true; + } + return false; + } + + /** + * Adds a token to $this->tokens + * + * @param mixed $type - the type. + * @param string $data - data. + * @param bool $do add a token even if preserve_css is off. + * @access private + * @version 1.0 + */ + public function _add_token( $type, $data, $do = false ) { // phpcs:ignore PSR2.Methods.MethodDeclaration.Underscore + if ( $this->get_cfg( 'preserve_css' ) || $do ) { + $this->tokens[] = array( $type, ( COMMENT === $type ) ? $data : trim( $data ) ); + } + } + + /** + * Add a message to the message log + * + * @param string $message - the message. + * @param string $type - the type of message. + * @param integer $line - the line. + * @access private + * @version 1.0 + */ + public function log( $message, $type, $line = -1 ) { + if ( -1 === $line ) { + $line = $this->line; + } + $line = (int) $line; + $add = array( + 'm' => $message, + 't' => $type, + ); + if ( ! isset( $this->log[ $line ] ) || ! in_array( $add, $this->log[ $line ], true ) ) { + $this->log[ $line ][] = $add; + } + } + + /** + * Parse unicode notations and find a replacement character + * + * @param string $string - a string. + * @param integer $i - counting integer. + * @access private + * @return string + * @version 1.2 + */ + public function _unicode( &$string, &$i ) { // phpcs:ignore PSR2.Methods.MethodDeclaration.Underscore + ++$i; + $add = ''; + $replaced = false; + + while ( $i < strlen( $string ) && ( ctype_xdigit( $string[ $i ] ) || ctype_space( $string[ $i ] ) ) && strlen( $add ) < 6 ) { // phpcs:ignore Squiz.PHP.DisallowSizeFunctionsInLoops.Found + $add .= $string[ $i ]; + + if ( ctype_space( $string[ $i ] ) ) { + break; + } + $i++; + } + + if ( hexdec( $add ) > 47 && hexdec( $add ) < 58 || hexdec( $add ) > 64 && hexdec( $add ) < 91 || hexdec( $add ) > 96 && hexdec( $add ) < 123 ) { + $this->log( 'Replaced unicode notation: Changed \\' . $add . ' to ' . chr( hexdec( $add ) ), 'Information' ); + $add = chr( hexdec( $add ) ); + $replaced = true; + } else { + $add = trim( '\\' . $add ); + } + + if ( @ctype_xdigit( $string[ $i + 1 ] ) && ctype_space( $string[ $i ] ) + && ! $replaced || ! ctype_space( $string[ $i ] ) ) { + $i--; + } + + if ( '\\' !== $add || ! $this->get_cfg( 'remove_bslash' ) || strpos( $this->tokens_list, $string[ $i + 1 ] ) !== false ) { + return $add; + } + + if ( '\\' === $add ) { + $this->log( 'Removed unnecessary backslash', 'Information' ); + } + return ''; + } + + /** + * Write formatted output to a file + * + * @param string $filename - the file na,e. + * @param string $doctype when printing formatted, is a shorthand for the document type. + * @param bool $externalcss when printing formatted, indicates whether styles to be attached internally or as an external stylesheet. + * @param string $title when printing formatted, is the title to be added in the head of the document. + * @param string $lang when printing formatted, gives a two-letter language code to be added to the output. + * @access public + * @version 1.4 + */ + public function write_page( $filename, $doctype = 'xhtml1.1', $externalcss = true, $title = '', $lang = 'en' ) { // phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable + $this->write( $filename, true ); + } + + /** + * Write plain output to a file + * + * @param string $filename the file name. + * @param bool $formatted whether to print formatted or not. + * @param string $doctype when printing formatted, is a shorthand for the document type. + * @param bool $externalcss when printing formatted, indicates whether styles to be attached internally or as an external stylesheet. + * @param string $title when printing formatted, is the title to be added in the head of the document. + * @param string $lang when printing formatted, gives a two-letter language code to be added to the output. + * @param bool $pre_code whether to add pre and code tags around the code (for light HTML formatted templates). + * @access public + * @version 1.4 + */ + public function write( $filename, $formatted = false, $doctype = 'xhtml1.1', $externalcss = true, $title = '', $lang = 'en', $pre_code = true ) { + $filename .= ( $formatted ) ? '.xhtml' : '.css'; + + if ( ! is_dir( 'temp' ) ) { + $madedir = mkdir( 'temp' ); + if ( ! $madedir ) { + print 'Could not make directory "temp" in ' . __DIR__; + exit; + } + } + $handle = fopen( 'temp/' . $filename, 'w' ); // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_read_fopen + if ( $handle ) { + if ( ! $formatted ) { + fwrite( $handle, $this->print->plain() ); // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_read_fwrite + } else { + fwrite( $handle, $this->print->formatted_page( $doctype, $externalcss, $title, $lang, $pre_code ) ); // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_read_fwrite + } + } + fclose( $handle ); // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_read_fclose + } + + /** + * Loads a new template + * + * @param string $content either filename (if $from_file == true), content of a template file, "high_compression", "highest_compression", "low_compression", or "default". + * @param bool $from_file uses $content as filename if true. + * @access public + * @version 1.1 + * @see http://csstidy.sourceforge.net/templates.php + */ + public function load_template( $content, $from_file = true ) { + $predefined_templates = & $GLOBALS['csstidy']['predefined_templates']; + if ( 'high_compression' === $content || 'default' === $content || 'highest_compression' === $content || 'low_compression' === $content ) { + $this->template = $predefined_templates[ $content ]; + return; + } + + if ( $from_file ) { + $content = strip_tags( file_get_contents( $content ), '<span>' ); // phpcs:ignore WordPress.WP.AlternativeFunctions.file_get_contents_file_get_contents + } + $content = str_replace( "\r\n", "\n", $content ); // Unify newlines (because the output also only uses \n). + $template = explode( '|', $content ); + + $this->template = array_replace( $this->template, $template ); + } + + /** + * Starts parsing from URL + * + * @param string $url - the URL. + * @access public + * @version 1.0 + */ + public function parse_from_url( $url ) { + return $this->parse( @file_get_contents( $url ) ); // phpcs:ignore WordPress.WP.AlternativeFunctions.file_get_contents_file_get_contents + } + + /** + * Checks if there is a token at the current position + * + * @param string $string - the string we're checking. + * @param integer $i - an int. + * @access public + * @version 1.11 + */ + public function is_token( &$string, $i ) { + return ( strpos( $this->tokens_list, $string[ $i ] ) !== false && ! self::escaped( $string, $i ) ); + } + + /** + * Parses CSS in $string. The code is saved as array in $this->css + * + * @param string $string the CSS code. + * @access public + * @return bool + * @version 1.1 + */ + public function parse( $string ) { + // Temporarily set locale to en_US in order to handle floats properly. + $old = @setlocale( LC_ALL, 0 ); + @setlocale( LC_ALL, 'C' ); + + // PHP bug? Settings need to be refreshed in PHP4. + $this->print = new csstidy_print( $this ); + + $at_rules = & $GLOBALS['csstidy']['at_rules']; + $quoted_string_properties = & $GLOBALS['csstidy']['quoted_string_properties']; + + $this->css = array(); + $this->print->input_css = $string; + $string = str_replace( "\r\n", "\n", $string ) . ' '; + $cur_comment = ''; + + for ( $i = 0, $size = strlen( $string ); $i < $size; $i++ ) { + if ( "\n" === $string[ $i ] || "\r" === $string[ $i ] ) { + ++$this->line; + } + + switch ( $this->status ) { + /* Case in at-block */ + case 'at': + if ( self::is_token( $string, $i ) ) { + if ( '/' === $string[ $i ] && '*' === @$string[ $i + 1 ] ) { + $this->status = 'ic'; + ++$i; + $this->from[] = 'at'; + } elseif ( '{' === $string[ $i ] ) { + $this->status = 'is'; + $this->at = $this->css_new_media_section( $this->at ); + $this->_add_token( AT_START, $this->at ); + } elseif ( ',' === $string[ $i ] ) { + $this->at = trim( $this->at ) . ','; + } elseif ( '\\' === $string[ $i ] ) { + $this->at .= $this->_unicode( $string, $i ); + } elseif ( in_array( $string[ $i ], array( '(', ')', ':', '.', '/' ), true ) ) { + // fix for complicated media, i.e @media screen and (-webkit-min-device-pixel-ratio:1.5) + // '/' is included for ratios in Opera: (-o-min-device-pixel-ratio: 3/2). + $this->at .= $string[ $i ]; + } + } else { + $lastpos = strlen( $this->at ) - 1; + if ( ! ( ( ctype_space( $this->at[ $lastpos ] ) || self::is_token( $this->at, $lastpos ) && ',' === $this->at[ $lastpos ] ) && ctype_space( $string[ $i ] ) ) ) { + $this->at .= $string[ $i ]; + } + } + break; + + /* Case in-selector */ + case 'is': + if ( self::is_token( $string, $i ) ) { + if ( '/' === $string[ $i ] && '*' === @$string[ $i + 1 ] && '' === trim( $this->selector ) ) { + $this->status = 'ic'; + ++$i; + $this->from[] = 'is'; + } elseif ( '@' === $string[ $i ] && '' === trim( $this->selector ) ) { + // Check for at-rule. + $this->invalid_at = true; + foreach ( $at_rules as $name => $type ) { + if ( ! strcasecmp( substr( $string, $i + 1, strlen( $name ) ), $name ) ) { + ( 'at' === $type ) ? $this->at = '@' . $name : $this->selector = '@' . $name; + $this->status = $type; + $i += strlen( $name ); + $this->invalid_at = false; + } + } + + if ( $this->invalid_at ) { + $this->selector = '@'; + $invalid_at_name = ''; + for ( $j = $i + 1; $j < $size; ++$j ) { + if ( ! ctype_alpha( $string[ $j ] ) ) { + break; + } + $invalid_at_name .= $string[ $j ]; + } + $this->log( 'Invalid @-rule: ' . $invalid_at_name . ' (removed)', 'Warning' ); + } + } elseif ( ( '"' === $string[ $i ] || "'" === $string[ $i ] ) ) { + $this->cur_string[] = $string[ $i ]; + $this->status = 'instr'; + $this->str_char[] = $string[ $i ]; + $this->from[] = 'is'; + /* fixing CSS3 attribute selectors, i.e. a[href$=".mp3" */ + $this->quoted_string[] = ( '=' === $string[ $i - 1 ] ); + } elseif ( $this->invalid_at && ';' === $string[ $i ] ) { + $this->invalid_at = false; + $this->status = 'is'; + } elseif ( '{' === $string[ $i ] ) { + $this->status = 'ip'; + if ( '' === $this->at ) { + $this->at = $this->css_new_media_section( DEFAULT_AT ); + } + $this->selector = $this->css_new_selector( $this->at, $this->selector ); + $this->_add_token( SEL_START, $this->selector ); + $this->added = false; + } elseif ( '}' === $string[ $i ] ) { + $this->_add_token( AT_END, $this->at ); + $this->at = ''; + $this->selector = ''; + $this->sel_separate = array(); + } elseif ( ',' === $string[ $i ] ) { + $this->selector = trim( $this->selector ) . ','; + $this->sel_separate[] = strlen( $this->selector ); + } elseif ( '\\' === $string[ $i ] ) { + $this->selector .= $this->_unicode( $string, $i ); + } elseif ( '*' === $string[ $i ] && @in_array( $string[ $i + 1 ], array( '.', '#', '[', ':' ), true ) ) { // phpcs:ignore Generic.CodeAnalysis.EmptyStatement.DetectedElseif + // remove unnecessary universal selector, FS#147. + } else { + $this->selector .= $string[ $i ]; + } + } else { + $lastpos = strlen( $this->selector ) - 1; + if ( -1 === $lastpos || ! ( ( ctype_space( $this->selector[ $lastpos ] ) || self::is_token( $this->selector, $lastpos ) && ',' === $this->selector[ $lastpos ] ) && ctype_space( $string[ $i ] ) ) ) { + $this->selector .= $string[ $i ]; + } elseif ( ctype_space( $string[ $i ] ) && $this->get_cfg( 'preserve_css' ) && ! $this->get_cfg( 'merge_selectors' ) ) { + $this->selector .= $string[ $i ]; + } + } + break; + + /* Case in-property */ + case 'ip': + if ( self::is_token( $string, $i ) ) { + if ( ( ':' === $string[ $i ] || '=' === $string[ $i ] ) && '' !== $this->property ) { + $this->status = 'iv'; + if ( ! $this->get_cfg( 'discard_invalid_properties' ) || self::property_is_valid( $this->property ) ) { + $this->property = $this->css_new_property( $this->at, $this->selector, $this->property ); + $this->_add_token( PROPERTY, $this->property ); + } + } elseif ( '/' === $string[ $i ] && '*' === @$string[ $i + 1 ] && '' === $this->property ) { + $this->status = 'ic'; + ++$i; + $this->from[] = 'ip'; + } elseif ( '}' === $string[ $i ] ) { + $this->explode_selectors(); + $this->status = 'is'; + $this->invalid_at = false; + $this->_add_token( SEL_END, $this->selector ); + $this->selector = ''; + $this->property = ''; + } elseif ( ';' === $string[ $i ] ) { + $this->property = ''; + } elseif ( '\\' === $string[ $i ] ) { + $this->property .= $this->_unicode( $string, $i ); + } elseif ( '' === $this->property && ! ctype_space( $string[ $i ] ) ) { + // else this is dumb IE a hack, keep it. + $this->property .= $string[ $i ]; + } + } elseif ( ! ctype_space( $string[ $i ] ) ) { + $this->property .= $string[ $i ]; + } + break; + + /* Case in-value */ + case 'iv': + $pn = ( ( "\n" === $string[ $i ] || "\r" === $string[ $i ] ) && $this->property_is_next( $string, $i + 1 ) || strlen( $string ) - 1 === $i ); + if ( ( self::is_token( $string, $i ) || $pn ) && ( ! ( ',' === $string[ $i ] && ! ctype_space( $string[ $i + 1 ] ) ) ) ) { + if ( '/' === $string[ $i ] && '*' === @$string[ $i + 1 ] ) { + $this->status = 'ic'; + ++$i; + $this->from[] = 'iv'; + } elseif ( ( '"' === $string[ $i ] || "'" === $string[ $i ] || '(' === $string[ $i ] ) ) { + $this->cur_string[] = $string[ $i ]; + $this->str_char[] = ( '(' === $string[ $i ] ) ? ')' : $string[ $i ]; + $this->status = 'instr'; + $this->from[] = 'iv'; + $this->quoted_string[] = in_array( strtolower( $this->property ), $quoted_string_properties, true ); + } elseif ( ',' === $string[ $i ] ) { + $this->sub_value = trim( $this->sub_value ) . ','; + } elseif ( '\\' === $string[ $i ] ) { + $this->sub_value .= $this->_unicode( $string, $i ); + } elseif ( ';' === $string[ $i ] || $pn ) { + if ( '@' === $this->selector[0] && isset( $at_rules[ substr( $this->selector, 1 ) ] ) && 'iv' === $at_rules[ substr( $this->selector, 1 ) ] ) { + $this->status = 'is'; + + switch ( $this->selector ) { + case '@charset': + /* Add quotes to charset */ + $this->sub_value_arr[] = '"' . trim( $this->sub_value ) . '"'; + $this->charset = $this->sub_value_arr[0]; + break; + case '@namespace': + /* Add quotes to namespace */ + $this->sub_value_arr[] = '"' . trim( $this->sub_value ) . '"'; + $this->namespace = implode( ' ', $this->sub_value_arr ); + break; + case '@import': + $this->sub_value = trim( $this->sub_value ); + + if ( empty( $this->sub_value_arr ) ) { + // Quote URLs in imports only if they're not already inside url() and not already quoted. + if ( substr( $this->sub_value, 0, 4 ) !== 'url(' ) { + if ( ! ( substr( $this->sub_value, -1 ) === $this->sub_value[0] && in_array( $this->sub_value[0], array( "'", '"' ), true ) ) ) { + $this->sub_value = '"' . $this->sub_value . '"'; + } + } + } + + $this->sub_value_arr[] = $this->sub_value; + $this->import[] = implode( ' ', $this->sub_value_arr ); + break; + } + + $this->sub_value_arr = array(); + $this->sub_value = ''; + $this->selector = ''; + $this->sel_separate = array(); + } else { + $this->status = 'ip'; + } + } elseif ( '}' !== $string[ $i ] ) { + $this->sub_value .= $string[ $i ]; + } + if ( ( '}' === $string[ $i ] || ';' === $string[ $i ] || $pn ) && ! empty( $this->selector ) ) { + if ( '' === $this->at ) { + $this->at = $this->css_new_media_section( DEFAULT_AT ); + } + + // case settings. + if ( $this->get_cfg( 'lowercase_s' ) ) { + $this->selector = strtolower( $this->selector ); + } + $this->property = strtolower( $this->property ); + + $this->optimise->subvalue(); + if ( '' !== $this->sub_value ) { + if ( substr( $this->sub_value, 0, 6 ) === 'format' ) { + $format_strings = self::parse_string_list( substr( $this->sub_value, 7, -1 ) ); + if ( ! $format_strings ) { + $this->sub_value = ''; + } else { + $this->sub_value = 'format('; + + foreach ( $format_strings as $format_string ) { + $this->sub_value .= '"' . str_replace( '"', '\\"', $format_string ) . '",'; + } + + $this->sub_value = substr( $this->sub_value, 0, -1 ) . ')'; + } + } + if ( '' !== $this->sub_value ) { + $this->sub_value_arr[] = $this->sub_value; + } + $this->sub_value = ''; + } + + $this->value = array_shift( $this->sub_value_arr ); + while ( $this->sub_value_arr ) { + $this->value .= ' ' . array_shift( $this->sub_value_arr ); + } + + $this->optimise->value(); + + $valid = self::property_is_valid( $this->property ); + if ( ( ! $this->invalid_at || $this->get_cfg( 'preserve_css' ) ) && ( ! $this->get_cfg( 'discard_invalid_properties' ) || $valid ) ) { + $this->css_add_property( $this->at, $this->selector, $this->property, $this->value ); + $this->_add_token( VALUE, $this->value ); + $this->optimise->shorthands(); + } + if ( ! $valid ) { + if ( $this->get_cfg( 'discard_invalid_properties' ) ) { + $this->log( 'Removed invalid property: ' . $this->property, 'Warning' ); + } else { + $this->log( 'Invalid property in ' . strtoupper( $this->get_cfg( 'css_level' ) ) . ': ' . $this->property, 'Warning' ); + } + } + + $this->property = ''; + $this->sub_value_arr = array(); + $this->value = ''; + } + if ( '}' === $string[ $i ] ) { + $this->explode_selectors(); + $this->_add_token( SEL_END, $this->selector ); + $this->status = 'is'; + $this->invalid_at = false; + $this->selector = ''; + } + } elseif ( ! $pn ) { + $this->sub_value .= $string[ $i ]; + + if ( ctype_space( $string[ $i ] ) || ',' === $string[ $i ] ) { + $this->optimise->subvalue(); + if ( '' !== $this->sub_value ) { + $this->sub_value_arr[] = $this->sub_value; + $this->sub_value = ''; + } + } + } + break; + + /* Case in string */ + case 'instr': + $_str_char = $this->str_char[ count( $this->str_char ) - 1 ]; + $_cur_string = $this->cur_string[ count( $this->cur_string ) - 1 ]; + $temp_add = $string[ $i ]; + + // Add another string to the stack. Strings can't be nested inside of quotes, only parentheses, but + // parentheticals can be nested more than once. + if ( ')' === $_str_char && ( '(' === $string[ $i ] || '"' === $string[ $i ] || '\'' === $string[ $i ] ) && ! self::escaped( $string, $i ) ) { + $this->cur_string[] = $string[ $i ]; + $this->str_char[] = $string[ $i ] === '(' ? ')' : $string[ $i ]; + $this->from[] = 'instr'; + $this->quoted_string[] = ! ( '(' === $string[ $i ] ); + continue 2; + } + + if ( ')' !== $_str_char && ( "\n" === $string[ $i ] || "\r" === $string[ $i ] ) && ! ( '\\' === $string[ $i - 1 ] && ! self::escaped( $string, $i - 1 ) ) ) { + $temp_add = '\\A'; + $this->log( 'Fixed incorrect newline in string', 'Warning' ); + } + + $_cur_string .= $temp_add; + + if ( $string[ $i ] === $_str_char && ! self::escaped( $string, $i ) ) { + $_quoted_string = array_pop( $this->quoted_string ); + + $this->status = array_pop( $this->from ); + + if ( ! preg_match( '|[' . implode( '', $GLOBALS['csstidy']['whitespace'] ) . ']|uis', $_cur_string ) && 'content' !== $this->property ) { + if ( ! $_quoted_string ) { + if ( ')' !== $_str_char ) { + // Convert properties like + // font-family: 'Arial'; + // to + // font-family: Arial; + // or + // url("abc") + // to + // url(abc). + $_cur_string = substr( $_cur_string, 1, -1 ); + } + } else { + $_quoted_string = false; + } + } + + array_pop( $this->cur_string ); + array_pop( $this->str_char ); + + if ( ')' === $_str_char ) { + $_cur_string = '(' . trim( substr( $_cur_string, 1, -1 ) ) . ')'; + } + + if ( 'iv' === $this->status ) { + if ( ! $_quoted_string ) { + if ( strpos( $_cur_string, ',' ) !== false ) { + // we can on only remove space next to ','. + $_cur_string = implode( ',', array_map( 'trim', explode( ',', $_cur_string ) ) ); + } + // and multiple spaces (too expensive). + if ( strpos( $_cur_string, ' ' ) !== false ) { + $_cur_string = preg_replace( ',\s+,', ' ', $_cur_string ); + } + } + $this->sub_value .= $_cur_string; + } elseif ( 'is' === $this->status ) { + $this->selector .= $_cur_string; + } elseif ( 'instr' === $this->status ) { + $this->cur_string[ count( $this->cur_string ) - 1 ] .= $_cur_string; + } + } else { + $this->cur_string[ count( $this->cur_string ) - 1 ] = $_cur_string; + } + break; + + /* Case in-comment */ + case 'ic': + if ( '*' === $string[ $i ] && '/' === $string[ $i + 1 ] ) { + $this->status = array_pop( $this->from ); + $i++; + $this->_add_token( COMMENT, $cur_comment ); + $cur_comment = ''; + } else { + $cur_comment .= $string[ $i ]; + } + break; + } + } + + $this->optimise->postparse(); + + $this->print->_reset(); + + @setlocale( LC_ALL, $old ); // Set locale back to original setting. + + return ! ( empty( $this->css ) && empty( $this->import ) && empty( $this->charset ) && empty( $this->tokens ) && empty( $this->namespace ) ); + } + + /** + * Explodes selectors + * + * @access private + * @version 1.0 + */ + public function explode_selectors() { + // Explode multiple selectors. + if ( $this->get_cfg( 'merge_selectors' ) === 1 ) { + $new_sels = array(); + $lastpos = 0; + $this->sel_separate[] = strlen( $this->selector ); + foreach ( $this->sel_separate as $num => $pos ) { + if ( count( $this->sel_separate ) - 1 === $num ) { + ++$pos; + } + + $new_sels[] = substr( $this->selector, $lastpos, $pos - $lastpos - 1 ); + $lastpos = $pos; + } + + if ( count( $new_sels ) > 1 ) { + foreach ( $new_sels as $selector ) { + if ( isset( $this->css[ $this->at ][ $this->selector ] ) ) { + $this->merge_css_blocks( $this->at, $selector, $this->css[ $this->at ][ $this->selector ] ); + } + } + unset( $this->css[ $this->at ][ $this->selector ] ); + } + } + $this->sel_separate = array(); + } + + /** + * Checks if a character is escaped (and returns true if it is) + * + * @param string $string - the string. + * @param integer $pos - the position. + * @access public + * @return bool + * @version 1.02 + */ + public static function escaped( &$string, $pos ) { + return ! ( @( '\\' !== $string[ $pos - 1 ] ) || self::escaped( $string, $pos - 1 ) ); + } + + /** + * Adds a property with value to the existing CSS code + * + * @param string $media - the media. + * @param string $selector - the selector. + * @param string $property - the property. + * @param string $new_val - new value. + * @access private + * @version 1.2 + */ + public function css_add_property( $media, $selector, $property, $new_val ) { + if ( $this->get_cfg( 'preserve_css' ) || '' === trim( $new_val ) ) { + return; + } + + $this->added = true; + if ( isset( $this->css[ $media ][ $selector ][ $property ] ) ) { + if ( ( self::is_important( $this->css[ $media ][ $selector ][ $property ] ) && self::is_important( $new_val ) ) || ! self::is_important( $this->css[ $media ][ $selector ][ $property ] ) ) { + $this->css[ $media ][ $selector ][ $property ] = trim( $new_val ); + } + } else { + $this->css[ $media ][ $selector ][ $property ] = trim( $new_val ); + } + } + + /** + * Start a new media section. + * Check if the media is not already known, + * else rename it with extra spaces + * to avoid merging + * + * @param string $media - the media. + * @return string + */ + public function css_new_media_section( $media ) { + if ( $this->get_cfg( 'preserve_css' ) ) { + return $media; + } + + // if the last @media is the same as this keep it. + if ( ! $this->css || ! is_array( $this->css ) || empty( $this->css ) ) { + return $media; + } + end( $this->css ); + $at = current( $this->css ); + if ( $at === $media ) { + return $media; + } + while ( isset( $this->css[ $media ] ) ) { + if ( is_numeric( $media ) ) { + $media++; + } else { + $media .= ' '; + } + } + return $media; + } + + /** + * Start a new selector. + * If already referenced in this media section, + * rename it with extra space to avoid merging + * except if merging is required, + * or last selector is the same (merge siblings) + * + * Never merge @font-face + * + * @param string $media - the media. + * @param string $selector - the selector. + * @return string + */ + public function css_new_selector( $media, $selector ) { + if ( $this->get_cfg( 'preserve_css' ) ) { + return $selector; + } + $selector = trim( $selector ); + if ( strncmp( $selector, '@font-face', 10 ) !== 0 ) { + if ( $this->settings['merge_selectors'] ) { + return $selector; + } + + if ( ! $this->css || ! isset( $this->css[ $media ] ) || ! $this->css[ $media ] ) { + return $selector; + } + + // if last is the same, keep it. + end( $this->css[ $media ] ); + $sel = current( $this->css[ $media ] ); + if ( $sel === $selector ) { + return $selector; + } + } + + while ( isset( $this->css[ $media ][ $selector ] ) ) { + $selector .= ' '; + } + return $selector; + } + + /** + * Start a new propertie. + * If already references in this selector, + * rename it with extra space to avoid override + * + * @param string $media - the media. + * @param string $selector - the selector. + * @param string $property - the property. + * @return string + */ + public function css_new_property( $media, $selector, $property ) { + if ( $this->get_cfg( 'preserve_css' ) ) { + return $property; + } + if ( ! $this->css || ! isset( $this->css[ $media ][ $selector ] ) || ! $this->css[ $media ][ $selector ] ) { + return $property; + } + + while ( isset( $this->css[ $media ][ $selector ][ $property ] ) ) { + $property .= ' '; + } + + return $property; + } + + /** + * Adds CSS to an existing media/selector + * + * @param string $media - the media. + * @param string $selector - the selector. + * @param array $css_add - css being added. + * @access private + * @version 1.1 + */ + public function merge_css_blocks( $media, $selector, $css_add ) { + foreach ( $css_add as $property => $value ) { + $this->css_add_property( $media, $selector, $property, $value, false ); + } + } + + /** + * Checks if $value is !important. + * + * @param string $value - the value. + * @return bool + * @access public + * @version 1.0 + */ + public static function is_important( &$value ) { + return ( ! strcasecmp( substr( str_replace( $GLOBALS['csstidy']['whitespace'], '', $value ), -10, 10 ), '!important' ) ); + } + + /** + * Returns a value without !important + * + * @param string $value - the value. + * @return string + * @access public + * @version 1.0 + */ + public static function gvw_important( $value ) { + if ( self::is_important( $value ) ) { + $value = trim( $value ); + $value = substr( $value, 0, -9 ); + $value = trim( $value ); + $value = substr( $value, 0, -1 ); + $value = trim( $value ); + return $value; + } + return $value; + } + + /** + * Checks if the next word in a string from pos is a CSS property + * + * @param string $istring - if it's a string. + * @param integer $pos - position. + * @return bool + * @access private + * @version 1.2 + */ + public function property_is_next( $istring, $pos ) { + $all_properties = & $GLOBALS['csstidy']['all_properties']; + $istring = substr( $istring, $pos, strlen( $istring ) - $pos ); + $pos = strpos( $istring, ':' ); + if ( false === $pos ) { + return false; + } + $istring = strtolower( trim( substr( $istring, 0, $pos ) ) ); + if ( isset( $all_properties[ $istring ] ) ) { + $this->log( 'Added semicolon to the end of declaration', 'Warning' ); + return true; + } + return false; + } + + /** + * Checks if a property is valid + * + * @param string $property - the property. + * @return bool; + * @access public + * @version 1.0 + */ + public function property_is_valid( $property ) { + $property = strtolower( $property ); + if ( in_array( trim( $property ), $GLOBALS['csstidy']['multiple_properties'], true ) ) { + $property = trim( $property ); + } + $all_properties = & $GLOBALS['csstidy']['all_properties']; + return ( isset( $all_properties[ $property ] ) && strpos( $all_properties[ $property ], strtoupper( $this->get_cfg( 'css_level' ) ) ) !== false ); + } + + /** + * Accepts a list of strings (e.g., the argument to format() in a @font-face src property) + * and returns a list of the strings. Converts things like: + * + * Format(abc) => format("abc") + * format(abc def) => format("abc","def") + * format(abc "def") => format("abc","def") + * format(abc, def, ghi) => format("abc","def","ghi") + * format("abc",'def') => format("abc","def") + * format("abc, def, ghi") => format("abc, def, ghi") + * + * @param string $value - the value. + * @return array + */ + public function parse_string_list( $value ) { + $value = trim( $value ); + + // Case: if it's empty. + if ( ! $value ) { + return array(); + } + + $strings = array(); + + $in_str = false; + $current_string = ''; + + for ( $i = 0, $_len = strlen( $value ); $i < $_len; $i++ ) { + if ( ( ',' === $value[ $i ] || ' ' === $value[ $i ] ) && true === $in_str ) { + $in_str = false; + $strings[] = $current_string; + $current_string = ''; + } elseif ( '"' === $value[ $i ] || "'" === $value[ $i ] ) { + if ( $in_str === $value[ $i ] ) { + $strings[] = $current_string; + $in_str = false; + $current_string = ''; + continue; + } elseif ( ! $in_str ) { + $in_str = $value[ $i ]; + } + } else { + if ( $in_str ) { + $current_string .= $value[ $i ]; + } else { + if ( ! preg_match( '/[\s,]/', $value[ $i ] ) ) { + $in_str = true; + $current_string = $value[ $i ]; + } + } + } + } + + if ( $current_string ) { + $strings[] = $current_string; + } + + return $strings; + } +} diff --git a/csstidy/cssparse-rtl.css b/csstidy/cssparse-rtl.css new file mode 100644 index 0000000..f04a746 --- /dev/null +++ b/csstidy/cssparse-rtl.css @@ -0,0 +1,146 @@ +code#copytext { + white-space: pre; + font-family: Verdana; +} + +.at { + color: darkblue; +} + +.format { + color: gray; +} + +.property { + color: green; +} + +.selector { + color: blue; +} + +.value { + color: red; + right: 500px; +} + +.comment { + color: orange; +} +html, body { + font: 0.8em Verdana, Helvetica, sans-serif; + background: #F8F8F6; +} + +code { + font-size: 1.2em; +} + +div#rightcol { + padding-right: 32em; +} + +fieldset { + display: block; + margin: 0.5em 0; + padding: 1em; + border: solid #7284AB 2px; +} + +fieldset.code_output { + display: inline; +} + +h1 { + font-size: 2em; +} + +small { + font-size: 0.7em; +} + +fieldset#field_input { + float: right; + margin: 0 0 1em 0.5em; +} + +fieldset#options, fieldset#code_layout { + width: 31em; +} + +input#submit { + clear: both; + display: block; + margin: 1em; +} + +select { + margin: 2px 0 0; +} + +label.block { + display: block; +} + +legend { + background: #c4E1C3; + padding: 2px 4px; + border: dashed 1px; +} + +textarea#css_text { + width: 27em; + height: 370px; + display: block; + margin-left: 1em; +} + +.help { + cursor: help; +} + +p.important { + border: solid 1px red; + font-weight: bold; + padding: 1em; + background: white; +} + +p { + margin: 1em 0; +} + +dl { + padding-right: 0.5em; +} + +dt { + font-weight: bold; + margin: 0; + float: right; + clear: both; + height: 1.5em; +} + +dd { + margin: 0 4em 0 0; + height: 1.5em; +} + +fieldset#messages { + background: white; + padding: 0 1em 0 0; +} + +fieldset#messages div { + height: 10em; + overflow: auto; +} + +dd.Warning { + color: orange; +} + +dd.Information { + color: green; +} diff --git a/csstidy/cssparse-rtl.min.css b/csstidy/cssparse-rtl.min.css new file mode 100644 index 0000000..cea0e4f --- /dev/null +++ b/csstidy/cssparse-rtl.min.css @@ -0,0 +1 @@ +code#copytext{font-family:Verdana;white-space:pre}.at{color:#00008b}.format{color:gray}.property{color:green}.selector{color:blue}.value{color:red;right:500px}.comment{color:orange}body,html{background:#f8f8f6;font:.8em Verdana,Helvetica,sans-serif}code{font-size:1.2em}div#rightcol{padding-right:32em}fieldset{border:2px solid #7284ab;display:block;margin:.5em 0;padding:1em}fieldset.code_output{display:inline}h1{font-size:2em}small{font-size:.7em}fieldset#field_input{float:right;margin:0 0 1em .5em}fieldset#code_layout,fieldset#options{width:31em}input#submit{clear:both;display:block;margin:1em}select{margin:2px 0 0}label.block{display:block}legend{background:#c4e1c3;border:1px dashed;padding:2px 4px}textarea#css_text{display:block;height:370px;margin-left:1em;width:27em}.help{cursor:help}p.important{background:#fff;border:1px solid red;font-weight:700;padding:1em}p{margin:1em 0}dl{padding-right:.5em}dt{clear:both;float:right;font-weight:700;margin:0}dd,dt{height:1.5em}dd{margin:0 4em 0 0}fieldset#messages{background:#fff;padding:0 1em 0 0}fieldset#messages div{height:10em;overflow:auto}dd.Warning{color:orange}dd.Information{color:green} \ No newline at end of file diff --git a/csstidy/cssparse.css b/csstidy/cssparse.css new file mode 100644 index 0000000..4dab9b5 --- /dev/null +++ b/csstidy/cssparse.css @@ -0,0 +1,118 @@ +@import url("./cssparsed.css"); + +html, body { +font:0.8em Verdana,Helvetica,sans-serif; +background:#F8F8F6; +} + +code { +font-size:1.2em; +} + +div#rightcol { +padding-left:32em; +} + +fieldset { +display:block; +margin:0.5em 0; +padding:1em; +border:solid #7284AB 2px; +} +fieldset.code_output { +display:inline; +} + +h1 { +font-size:2em; +} + +small { +font-size:0.7em; +} + +fieldset#field_input { +float:left; +margin:0 0.5em 1em 0; +} + +fieldset#options,fieldset#code_layout { +width:31em; +} + +input#submit { +clear:both; +display:block; +margin:1em; +} + +select { +margin:2px 0 0; +} + +label.block { +display:block; +} + +legend { +background:#c4E1C3; +padding:2px 4px; +border:dashed 1px; +} + +textarea#css_text { +width:27em; +height:370px; +display:block; +margin-right:1em; +} + +.help { +cursor:help; +} + +p.important { +border:solid 1px red; +font-weight:bold; +padding:1em; +background:white; +} + +p { +margin:1em 0; +} + +dl { +padding-left:0.5em; +} + +dt { +font-weight:bold; +margin:0; +float:left; +clear:both; +height:1.5em; +} + +dd { +margin:0 0 0 4em; +height:1.5em; +} + +fieldset#messages { +background:white; +padding:0 0 0 1em; +} + +fieldset#messages div { +height:10em; +overflow:auto; +} + +dd.Warning { +color:orange; +} + +dd.Information { +color:green; +} diff --git a/csstidy/cssparse.min.css b/csstidy/cssparse.min.css new file mode 100644 index 0000000..74aaa8b --- /dev/null +++ b/csstidy/cssparse.min.css @@ -0,0 +1 @@ +code#copytext{font-family:Verdana;white-space:pre}.at{color:#00008b}.format{color:gray}.property{color:green}.selector{color:blue}.value{color:red;left:500px}.comment{color:orange}body,html{background:#f8f8f6;font:.8em Verdana,Helvetica,sans-serif}code{font-size:1.2em}div#rightcol{padding-left:32em}fieldset{border:2px solid #7284ab;display:block;margin:.5em 0;padding:1em}fieldset.code_output{display:inline}h1{font-size:2em}small{font-size:.7em}fieldset#field_input{float:left;margin:0 .5em 1em 0}fieldset#code_layout,fieldset#options{width:31em}input#submit{clear:both;display:block;margin:1em}select{margin:2px 0 0}label.block{display:block}legend{background:#c4e1c3;border:1px dashed;padding:2px 4px}textarea#css_text{display:block;height:370px;margin-right:1em;width:27em}.help{cursor:help}p.important{background:#fff;border:1px solid red;font-weight:700;padding:1em}p{margin:1em 0}dl{padding-left:.5em}dt{clear:both;float:left;font-weight:700;margin:0}dd,dt{height:1.5em}dd{margin:0 0 0 4em}fieldset#messages{background:#fff;padding:0 0 0 1em}fieldset#messages div{height:10em;overflow:auto}dd.Warning{color:orange}dd.Information{color:green} \ No newline at end of file diff --git a/csstidy/cssparsed-rtl.css b/csstidy/cssparsed-rtl.css new file mode 100644 index 0000000..5b8877a --- /dev/null +++ b/csstidy/cssparsed-rtl.css @@ -0,0 +1,29 @@ +code#copytext { + white-space: pre; + font-family: Verdana; +} + +.at { + color: darkblue; +} + +.format { + color: gray; +} + +.property { + color: green; +} + +.selector { + color: blue; +} + +.value { + color: red; + right: 500px; +} + +.comment { + color: orange; +} diff --git a/csstidy/cssparsed-rtl.min.css b/csstidy/cssparsed-rtl.min.css new file mode 100644 index 0000000..99cd80f --- /dev/null +++ b/csstidy/cssparsed-rtl.min.css @@ -0,0 +1 @@ +code#copytext{font-family:Verdana;white-space:pre}.at{color:#00008b}.format{color:gray}.property{color:green}.selector{color:blue}.value{color:red;right:500px}.comment{color:orange} \ No newline at end of file diff --git a/csstidy/cssparsed.css b/csstidy/cssparsed.css new file mode 100644 index 0000000..5aaf2bb --- /dev/null +++ b/csstidy/cssparsed.css @@ -0,0 +1,29 @@ +code#copytext { + white-space: pre; + font-family: Verdana; +} + +.at { +color:darkblue; +} + +.format { +color:gray; +} + +.property { +color:green; +} + +.selector { +color:blue; +} + +.value { +color:red; +left: 500px; +} + +.comment { +color:orange; +} \ No newline at end of file diff --git a/csstidy/cssparsed.min.css b/csstidy/cssparsed.min.css new file mode 100644 index 0000000..76b0020 --- /dev/null +++ b/csstidy/cssparsed.min.css @@ -0,0 +1 @@ +code#copytext{font-family:Verdana;white-space:pre}.at{color:#00008b}.format{color:gray}.property{color:green}.selector{color:blue}.value{color:red;left:500px}.comment{color:orange} \ No newline at end of file diff --git a/csstidy/data-wp.inc.php b/csstidy/data-wp.inc.php new file mode 100644 index 0000000..518a5bb --- /dev/null +++ b/csstidy/data-wp.inc.php @@ -0,0 +1,102 @@ +<?php // phpcs:ignore WordPress.Files.FileName.InvalidClassFileName + +unset( $GLOBALS['csstidy']['all_properties']['binding'] ); + +$GLOBALS['csstidy']['all_properties']['text-size-adjust'] = 'CSS3.0'; + +// Support browser prefixes for properties only in the latest CSS draft +foreach ( $GLOBALS['csstidy']['all_properties'] as $property => $levels ) { + if ( strpos( $levels, ',' ) === false ) { + $GLOBALS['csstidy']['all_properties'][ '-moz-' . $property ] = $levels; + $GLOBALS['csstidy']['all_properties'][ '-webkit-' . $property ] = $levels; + $GLOBALS['csstidy']['all_properties'][ '-ms-' . $property ] = $levels; + $GLOBALS['csstidy']['all_properties'][ '-o-' . $property ] = $levels; + $GLOBALS['csstidy']['all_properties'][ '-khtml-' . $property ] = $levels; + + if ( in_array( $property, $GLOBALS['csstidy']['unit_values'], true ) ) { + $GLOBALS['csstidy']['unit_values'][] = '-moz-' . $property; + $GLOBALS['csstidy']['unit_values'][] = '-webkit-' . $property; + $GLOBALS['csstidy']['unit_values'][] = '-ms-' . $property; + $GLOBALS['csstidy']['unit_values'][] = '-o-' . $property; + $GLOBALS['csstidy']['unit_values'][] = '-khtml-' . $property; + } + + if ( in_array( $property, $GLOBALS['csstidy']['color_values'], true ) ) { + $GLOBALS['csstidy']['color_values'][] = '-moz-' . $property; + $GLOBALS['csstidy']['color_values'][] = '-webkit-' . $property; + $GLOBALS['csstidy']['color_values'][] = '-ms-' . $property; + $GLOBALS['csstidy']['color_values'][] = '-o-' . $property; + $GLOBALS['csstidy']['color_values'][] = '-khtml-' . $property; + } + } +} + +// Add `display` to the list of properties that can be used multiple times in a single selector +$GLOBALS['csstidy']['multiple_properties'][] = 'display'; + +// Allow vendor prefixes for any property that is allowed to be used multiple times inside a single selector +foreach ( $GLOBALS['csstidy']['multiple_properties'] as $property ) { + if ( '-' !== $property[0] ) { + $GLOBALS['csstidy']['multiple_properties'][] = '-o-' . $property; + $GLOBALS['csstidy']['multiple_properties'][] = '-ms-' . $property; + $GLOBALS['csstidy']['multiple_properties'][] = '-webkit-' . $property; + $GLOBALS['csstidy']['multiple_properties'][] = '-moz-' . $property; + $GLOBALS['csstidy']['multiple_properties'][] = '-khtml-' . $property; + } +} + +/** + * CSS Animation + * + * @see https://developer.mozilla.org/en/CSS/CSS_animations + */ +$GLOBALS['csstidy']['at_rules']['-webkit-keyframes'] = 'at'; +$GLOBALS['csstidy']['at_rules']['-moz-keyframes'] = 'at'; +$GLOBALS['csstidy']['at_rules']['-ms-keyframes'] = 'at'; +$GLOBALS['csstidy']['at_rules']['-o-keyframes'] = 'at'; + +/** + * Non-standard viewport rule. + */ +$GLOBALS['csstidy']['at_rules']['viewport'] = 'is'; +$GLOBALS['csstidy']['at_rules']['-webkit-viewport'] = 'is'; +$GLOBALS['csstidy']['at_rules']['-moz-viewport'] = 'is'; +$GLOBALS['csstidy']['at_rules']['-ms-viewport'] = 'is'; + +/** + * Non-standard CSS properties. They're not part of any spec, but we say + * they're in all of them so that we can support them. + */ +$GLOBALS['csstidy']['all_properties']['-webkit-filter'] = 'CSS2.0,CSS2.1,CSS3.0'; +$GLOBALS['csstidy']['all_properties']['-moz-filter'] = 'CSS2.0,CSS2.1,CSS3.0'; +$GLOBALS['csstidy']['all_properties']['-ms-filter'] = 'CSS2.0,CSS2.1,CSS3.0'; +$GLOBALS['csstidy']['all_properties']['filter'] = 'CSS2.0,CSS2.1,CSS3.0'; +$GLOBALS['csstidy']['all_properties']['scrollbar-face-color'] = 'CSS2.0,CSS2.1,CSS3.0'; +$GLOBALS['csstidy']['all_properties']['-ms-interpolation-mode'] = 'CSS2.0,CSS2.1,CSS3.0'; +$GLOBALS['csstidy']['all_properties']['text-rendering'] = 'CSS2.0,CSS2.1,CSS3.0'; +$GLOBALS['csstidy']['all_properties']['-webkit-transform-origin-x'] = 'CSS3.0'; +$GLOBALS['csstidy']['all_properties']['-webkit-transform-origin-y'] = 'CSS3.0'; +$GLOBALS['csstidy']['all_properties']['-webkit-transform-origin-z'] = 'CSS3.0'; +$GLOBALS['csstidy']['all_properties']['-webkit-font-smoothing'] = 'CSS3.0'; +$GLOBALS['csstidy']['all_properties']['-moz-osx-font-smoothing'] = 'CSS3.0'; +$GLOBALS['csstidy']['all_properties']['-font-smooth'] = 'CSS3.0'; +$GLOBALS['csstidy']['all_properties']['-o-object-fit'] = 'CSS3.0'; +$GLOBALS['csstidy']['all_properties']['object-fit'] = 'CSS3.0'; +$GLOBALS['csstidy']['all_properties']['-o-object-position'] = 'CSS3.0'; +$GLOBALS['csstidy']['all_properties']['object-position'] = 'CSS3.0'; +$GLOBALS['csstidy']['all_properties']['text-overflow'] = 'CSS3.0'; +$GLOBALS['csstidy']['all_properties']['zoom'] = 'CSS3.0'; +$GLOBALS['csstidy']['all_properties']['pointer-events'] = 'CSS3.0'; +$GLOBALS['csstidy']['all_properties']['font-feature-settings'] = 'CSS3.0'; +$GLOBALS['csstidy']['all_properties']['font-kerning'] = 'CSS3.0'; +$GLOBALS['csstidy']['all_properties']['font-language-override'] = 'CSS3.0'; +$GLOBALS['csstidy']['all_properties']['font-synthesis'] = 'CSS3.0'; +$GLOBALS['csstidy']['all_properties']['font-variant-alternates'] = 'CSS3.0'; +$GLOBALS['csstidy']['all_properties']['font-variant-caps'] = 'CSS3.0'; +$GLOBALS['csstidy']['all_properties']['font-variant-east-asian'] = 'CSS3.0'; +$GLOBALS['csstidy']['all_properties']['font-variant-ligatures'] = 'CSS3.0'; +$GLOBALS['csstidy']['all_properties']['font-variant-numeric'] = 'CSS3.0'; +$GLOBALS['csstidy']['all_properties']['font-variant-position'] = 'CSS3.0'; +$GLOBALS['csstidy']['all_properties']['font-variation-settings'] = 'CSS3.0'; +$GLOBALS['csstidy']['all_properties']['line-height-step'] = 'CSS3.0'; + diff --git a/csstidy/data.inc.php b/csstidy/data.inc.php new file mode 100644 index 0000000..f88579a --- /dev/null +++ b/csstidy/data.inc.php @@ -0,0 +1,777 @@ +<?php +/** + * Various CSS Data for CSSTidy + * + * This file is part of CSSTidy. + * + * CSSTidy is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * CSSTidy is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with CSSTidy; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + * @license https://opensource.org/licenses/gpl-license.php GNU Public License + * @package csstidy + * @author Florian Schmitz (floele at gmail dot com) 2005, Nikolay Matsievsky (speed at webo dot name) 2010 + */ + +define( 'AT_START', 1 ); +define( 'AT_END', 2 ); +define( 'SEL_START', 3 ); +define( 'SEL_END', 4 ); +define( 'PROPERTY', 5 ); +define( 'VALUE', 6 ); +define( 'COMMENT', 7 ); +define( 'DEFAULT_AT', 41 ); + +/** + * All whitespace allowed in CSS + * + * @global array $GLOBALS['csstidy']['whitespace'] + * @version 1.0 + */ +$GLOBALS['csstidy']['whitespace'] = array( ' ', "\n", "\t", "\r", "\x0B" ); + +/** + * All CSS tokens used by csstidy + * + * @global string $GLOBALS['csstidy']['tokens'] + * @version 1.0 + */ +$GLOBALS['csstidy']['tokens'] = '/@}{;:=\'"(,\\!$%&)*+.<>?[]^`|~'; + +/** + * All CSS units (CSS 3 units included) + * + * @see compress_numbers() + * @global array $GLOBALS['csstidy']['units'] + * @version 1.0 + */ +$GLOBALS['csstidy']['units'] = array( 'in', 'cm', 'mm', 'pt', 'pc', 'px', 'rem', 'em', '%', 'ex', 'gd', 'vw', 'vh', 'vm', 'deg', 'grad', 'rad', 'ms', 's', 'khz', 'hz' ); + +/** + * Available at-rules + * + * @global array $GLOBALS['csstidy']['at_rules'] + * @version 1.0 + */ +$GLOBALS['csstidy']['at_rules'] = array( + 'page' => 'is', + 'font-face' => 'is', + 'charset' => 'iv', + 'import' => 'iv', + 'namespace' => 'iv', + 'media' => 'at', + 'keyframes' => 'at', + 'supports' => 'at', +); + +/** + * Properties that need a value with unit + * + * @todo CSS3 properties + * @see compress_numbers(); + * @global array $GLOBALS['csstidy']['unit_values'] + * @version 1.2 + */ +$GLOBALS['csstidy']['unit_values'] = array( + 'background', + 'background-position', + 'background-size', + 'border', + 'border-top', + 'border-right', + 'border-bottom', + 'border-left', + 'border-width', + 'border-top-width', + 'border-right-width', + 'border-left-width', + 'border-bottom-width', + 'bottom', + 'border-spacing', + 'column-gap', + 'column-width', + 'font-size', + 'height', + 'left', + 'margin', + 'margin-top', + 'margin-right', + 'margin-bottom', + 'margin-left', + 'max-height', + 'max-width', + 'min-height', + 'min-width', + 'outline', + 'outline-width', + 'padding', + 'padding-top', + 'padding-right', + 'padding-bottom', + 'padding-left', + 'perspective', + 'right', + 'top', + 'text-indent', + 'letter-spacing', + 'word-spacing', + 'width', +); + +/** + * Properties that allow <color> as value + * + * @todo CSS3 properties + * @see compress_numbers(); + * @global array $GLOBALS['csstidy']['color_values'] + * @version 1.0 + */ +$GLOBALS['csstidy']['color_values'] = array(); +$GLOBALS['csstidy']['color_values'][] = 'background-color'; +$GLOBALS['csstidy']['color_values'][] = 'border-color'; +$GLOBALS['csstidy']['color_values'][] = 'border-top-color'; +$GLOBALS['csstidy']['color_values'][] = 'border-right-color'; +$GLOBALS['csstidy']['color_values'][] = 'border-bottom-color'; +$GLOBALS['csstidy']['color_values'][] = 'border-left-color'; +$GLOBALS['csstidy']['color_values'][] = 'color'; +$GLOBALS['csstidy']['color_values'][] = 'outline-color'; +$GLOBALS['csstidy']['color_values'][] = 'column-rule-color'; + +/** + * Default values for the background properties + * + * @todo Possibly property names will change during CSS3 development + * @global array $GLOBALS['csstidy']['background_prop_default'] + * @see dissolve_short_bg() + * @see merge_bg() + * @version 1.0 + */ +$GLOBALS['csstidy']['background_prop_default'] = array(); +$GLOBALS['csstidy']['background_prop_default']['background-image'] = 'none'; +$GLOBALS['csstidy']['background_prop_default']['background-size'] = 'auto'; +$GLOBALS['csstidy']['background_prop_default']['background-repeat'] = 'repeat'; +$GLOBALS['csstidy']['background_prop_default']['background-position'] = '0 0'; +$GLOBALS['csstidy']['background_prop_default']['background-attachment'] = 'scroll'; +$GLOBALS['csstidy']['background_prop_default']['background-clip'] = 'border'; +$GLOBALS['csstidy']['background_prop_default']['background-origin'] = 'padding'; +$GLOBALS['csstidy']['background_prop_default']['background-color'] = 'transparent'; + +/** + * Default values for the font properties + * + * @global array $GLOBALS['csstidy']['font_prop_default'] + * @see merge_fonts() + * @version 1.3 + */ +$GLOBALS['csstidy']['font_prop_default'] = array(); +$GLOBALS['csstidy']['font_prop_default']['font-style'] = 'normal'; +$GLOBALS['csstidy']['font_prop_default']['font-variant'] = 'normal'; +$GLOBALS['csstidy']['font_prop_default']['font-weight'] = 'normal'; +$GLOBALS['csstidy']['font_prop_default']['font-size'] = ''; +$GLOBALS['csstidy']['font_prop_default']['line-height'] = ''; +$GLOBALS['csstidy']['font_prop_default']['font-family'] = ''; + +/** + * A list of non-W3C color names which get replaced by their hex-codes + * + * @global array $GLOBALS['csstidy']['replace_colors'] + * @see cut_color() + * @version 1.0 + */ +$GLOBALS['csstidy']['replace_colors'] = array(); +$GLOBALS['csstidy']['replace_colors']['aliceblue'] = '#f0f8ff'; +$GLOBALS['csstidy']['replace_colors']['antiquewhite'] = '#faebd7'; +$GLOBALS['csstidy']['replace_colors']['aquamarine'] = '#7fffd4'; +$GLOBALS['csstidy']['replace_colors']['azure'] = '#f0ffff'; +$GLOBALS['csstidy']['replace_colors']['beige'] = '#f5f5dc'; +$GLOBALS['csstidy']['replace_colors']['bisque'] = '#ffe4c4'; +$GLOBALS['csstidy']['replace_colors']['blanchedalmond'] = '#ffebcd'; +$GLOBALS['csstidy']['replace_colors']['blueviolet'] = '#8a2be2'; +$GLOBALS['csstidy']['replace_colors']['brown'] = '#a52a2a'; +$GLOBALS['csstidy']['replace_colors']['burlywood'] = '#deb887'; +$GLOBALS['csstidy']['replace_colors']['cadetblue'] = '#5f9ea0'; +$GLOBALS['csstidy']['replace_colors']['chartreuse'] = '#7fff00'; +$GLOBALS['csstidy']['replace_colors']['chocolate'] = '#d2691e'; +$GLOBALS['csstidy']['replace_colors']['coral'] = '#ff7f50'; +$GLOBALS['csstidy']['replace_colors']['cornflowerblue'] = '#6495ed'; +$GLOBALS['csstidy']['replace_colors']['cornsilk'] = '#fff8dc'; +$GLOBALS['csstidy']['replace_colors']['crimson'] = '#dc143c'; +$GLOBALS['csstidy']['replace_colors']['cyan'] = '#00ffff'; +$GLOBALS['csstidy']['replace_colors']['darkblue'] = '#00008b'; +$GLOBALS['csstidy']['replace_colors']['darkcyan'] = '#008b8b'; +$GLOBALS['csstidy']['replace_colors']['darkgoldenrod'] = '#b8860b'; +$GLOBALS['csstidy']['replace_colors']['darkgray'] = '#a9a9a9'; +$GLOBALS['csstidy']['replace_colors']['darkgreen'] = '#006400'; +$GLOBALS['csstidy']['replace_colors']['darkkhaki'] = '#bdb76b'; +$GLOBALS['csstidy']['replace_colors']['darkmagenta'] = '#8b008b'; +$GLOBALS['csstidy']['replace_colors']['darkolivegreen'] = '#556b2f'; +$GLOBALS['csstidy']['replace_colors']['darkorange'] = '#ff8c00'; +$GLOBALS['csstidy']['replace_colors']['darkorchid'] = '#9932cc'; +$GLOBALS['csstidy']['replace_colors']['darkred'] = '#8b0000'; +$GLOBALS['csstidy']['replace_colors']['darksalmon'] = '#e9967a'; +$GLOBALS['csstidy']['replace_colors']['darkseagreen'] = '#8fbc8f'; +$GLOBALS['csstidy']['replace_colors']['darkslateblue'] = '#483d8b'; +$GLOBALS['csstidy']['replace_colors']['darkslategray'] = '#2f4f4f'; +$GLOBALS['csstidy']['replace_colors']['darkturquoise'] = '#00ced1'; +$GLOBALS['csstidy']['replace_colors']['darkviolet'] = '#9400d3'; +$GLOBALS['csstidy']['replace_colors']['deeppink'] = '#ff1493'; +$GLOBALS['csstidy']['replace_colors']['deepskyblue'] = '#00bfff'; +$GLOBALS['csstidy']['replace_colors']['dimgray'] = '#696969'; +$GLOBALS['csstidy']['replace_colors']['dodgerblue'] = '#1e90ff'; +$GLOBALS['csstidy']['replace_colors']['feldspar'] = '#d19275'; +$GLOBALS['csstidy']['replace_colors']['firebrick'] = '#b22222'; +$GLOBALS['csstidy']['replace_colors']['floralwhite'] = '#fffaf0'; +$GLOBALS['csstidy']['replace_colors']['forestgreen'] = '#228b22'; +$GLOBALS['csstidy']['replace_colors']['gainsboro'] = '#dcdcdc'; +$GLOBALS['csstidy']['replace_colors']['ghostwhite'] = '#f8f8ff'; +$GLOBALS['csstidy']['replace_colors']['gold'] = '#ffd700'; +$GLOBALS['csstidy']['replace_colors']['goldenrod'] = '#daa520'; +$GLOBALS['csstidy']['replace_colors']['greenyellow'] = '#adff2f'; +$GLOBALS['csstidy']['replace_colors']['honeydew'] = '#f0fff0'; +$GLOBALS['csstidy']['replace_colors']['hotpink'] = '#ff69b4'; +$GLOBALS['csstidy']['replace_colors']['indianred'] = '#cd5c5c'; +$GLOBALS['csstidy']['replace_colors']['indigo'] = '#4b0082'; +$GLOBALS['csstidy']['replace_colors']['ivory'] = '#fffff0'; +$GLOBALS['csstidy']['replace_colors']['khaki'] = '#f0e68c'; +$GLOBALS['csstidy']['replace_colors']['lavender'] = '#e6e6fa'; +$GLOBALS['csstidy']['replace_colors']['lavenderblush'] = '#fff0f5'; +$GLOBALS['csstidy']['replace_colors']['lawngreen'] = '#7cfc00'; +$GLOBALS['csstidy']['replace_colors']['lemonchiffon'] = '#fffacd'; +$GLOBALS['csstidy']['replace_colors']['lightblue'] = '#add8e6'; +$GLOBALS['csstidy']['replace_colors']['lightcoral'] = '#f08080'; +$GLOBALS['csstidy']['replace_colors']['lightcyan'] = '#e0ffff'; +$GLOBALS['csstidy']['replace_colors']['lightgoldenrodyellow'] = '#fafad2'; +$GLOBALS['csstidy']['replace_colors']['lightgrey'] = '#d3d3d3'; +$GLOBALS['csstidy']['replace_colors']['lightgreen'] = '#90ee90'; +$GLOBALS['csstidy']['replace_colors']['lightpink'] = '#ffb6c1'; +$GLOBALS['csstidy']['replace_colors']['lightsalmon'] = '#ffa07a'; +$GLOBALS['csstidy']['replace_colors']['lightseagreen'] = '#20b2aa'; +$GLOBALS['csstidy']['replace_colors']['lightskyblue'] = '#87cefa'; +$GLOBALS['csstidy']['replace_colors']['lightslateblue'] = '#8470ff'; +$GLOBALS['csstidy']['replace_colors']['lightslategray'] = '#778899'; +$GLOBALS['csstidy']['replace_colors']['lightsteelblue'] = '#b0c4de'; +$GLOBALS['csstidy']['replace_colors']['lightyellow'] = '#ffffe0'; +$GLOBALS['csstidy']['replace_colors']['limegreen'] = '#32cd32'; +$GLOBALS['csstidy']['replace_colors']['linen'] = '#faf0e6'; +$GLOBALS['csstidy']['replace_colors']['magenta'] = '#ff00ff'; +$GLOBALS['csstidy']['replace_colors']['mediumaquamarine'] = '#66cdaa'; +$GLOBALS['csstidy']['replace_colors']['mediumblue'] = '#0000cd'; +$GLOBALS['csstidy']['replace_colors']['mediumorchid'] = '#ba55d3'; +$GLOBALS['csstidy']['replace_colors']['mediumpurple'] = '#9370d8'; +$GLOBALS['csstidy']['replace_colors']['mediumseagreen'] = '#3cb371'; +$GLOBALS['csstidy']['replace_colors']['mediumslateblue'] = '#7b68ee'; +$GLOBALS['csstidy']['replace_colors']['mediumspringgreen'] = '#00fa9a'; +$GLOBALS['csstidy']['replace_colors']['mediumturquoise'] = '#48d1cc'; +$GLOBALS['csstidy']['replace_colors']['mediumvioletred'] = '#c71585'; +$GLOBALS['csstidy']['replace_colors']['midnightblue'] = '#191970'; +$GLOBALS['csstidy']['replace_colors']['mintcream'] = '#f5fffa'; +$GLOBALS['csstidy']['replace_colors']['mistyrose'] = '#ffe4e1'; +$GLOBALS['csstidy']['replace_colors']['moccasin'] = '#ffe4b5'; +$GLOBALS['csstidy']['replace_colors']['navajowhite'] = '#ffdead'; +$GLOBALS['csstidy']['replace_colors']['oldlace'] = '#fdf5e6'; +$GLOBALS['csstidy']['replace_colors']['olivedrab'] = '#6b8e23'; +$GLOBALS['csstidy']['replace_colors']['orangered'] = '#ff4500'; +$GLOBALS['csstidy']['replace_colors']['orchid'] = '#da70d6'; +$GLOBALS['csstidy']['replace_colors']['palegoldenrod'] = '#eee8aa'; +$GLOBALS['csstidy']['replace_colors']['palegreen'] = '#98fb98'; +$GLOBALS['csstidy']['replace_colors']['paleturquoise'] = '#afeeee'; +$GLOBALS['csstidy']['replace_colors']['palevioletred'] = '#d87093'; +$GLOBALS['csstidy']['replace_colors']['papayawhip'] = '#ffefd5'; +$GLOBALS['csstidy']['replace_colors']['peachpuff'] = '#ffdab9'; +$GLOBALS['csstidy']['replace_colors']['peru'] = '#cd853f'; +$GLOBALS['csstidy']['replace_colors']['pink'] = '#ffc0cb'; +$GLOBALS['csstidy']['replace_colors']['plum'] = '#dda0dd'; +$GLOBALS['csstidy']['replace_colors']['powderblue'] = '#b0e0e6'; +$GLOBALS['csstidy']['replace_colors']['rosybrown'] = '#bc8f8f'; +$GLOBALS['csstidy']['replace_colors']['royalblue'] = '#4169e1'; +$GLOBALS['csstidy']['replace_colors']['saddlebrown'] = '#8b4513'; +$GLOBALS['csstidy']['replace_colors']['salmon'] = '#fa8072'; +$GLOBALS['csstidy']['replace_colors']['sandybrown'] = '#f4a460'; +$GLOBALS['csstidy']['replace_colors']['seagreen'] = '#2e8b57'; +$GLOBALS['csstidy']['replace_colors']['seashell'] = '#fff5ee'; +$GLOBALS['csstidy']['replace_colors']['sienna'] = '#a0522d'; +$GLOBALS['csstidy']['replace_colors']['skyblue'] = '#87ceeb'; +$GLOBALS['csstidy']['replace_colors']['slateblue'] = '#6a5acd'; +$GLOBALS['csstidy']['replace_colors']['slategray'] = '#708090'; +$GLOBALS['csstidy']['replace_colors']['snow'] = '#fffafa'; +$GLOBALS['csstidy']['replace_colors']['springgreen'] = '#00ff7f'; +$GLOBALS['csstidy']['replace_colors']['steelblue'] = '#4682b4'; +$GLOBALS['csstidy']['replace_colors']['tan'] = '#d2b48c'; +$GLOBALS['csstidy']['replace_colors']['thistle'] = '#d8bfd8'; +$GLOBALS['csstidy']['replace_colors']['tomato'] = '#ff6347'; +$GLOBALS['csstidy']['replace_colors']['turquoise'] = '#40e0d0'; +$GLOBALS['csstidy']['replace_colors']['violet'] = '#ee82ee'; +$GLOBALS['csstidy']['replace_colors']['violetred'] = '#d02090'; +$GLOBALS['csstidy']['replace_colors']['wheat'] = '#f5deb3'; +$GLOBALS['csstidy']['replace_colors']['whitesmoke'] = '#f5f5f5'; +$GLOBALS['csstidy']['replace_colors']['yellowgreen'] = '#9acd32'; + +/** + * A list of all shorthand properties that are divided into four properties and/or have four subvalues + * + * @global array $GLOBALS['csstidy']['shorthands'] + * @todo Are there new ones in CSS3? + * @see dissolve_4value_shorthands() + * @see merge_4value_shorthands() + * @version 1.0 + */ +$GLOBALS['csstidy']['shorthands'] = array(); +$GLOBALS['csstidy']['shorthands']['border-color'] = array( 'border-top-color', 'border-right-color', 'border-bottom-color', 'border-left-color' ); +$GLOBALS['csstidy']['shorthands']['border-style'] = array( 'border-top-style', 'border-right-style', 'border-bottom-style', 'border-left-style' ); +$GLOBALS['csstidy']['shorthands']['border-width'] = array( 'border-top-width', 'border-right-width', 'border-bottom-width', 'border-left-width' ); +$GLOBALS['csstidy']['shorthands']['margin'] = array( 'margin-top', 'margin-right', 'margin-bottom', 'margin-left' ); +$GLOBALS['csstidy']['shorthands']['padding'] = array( 'padding-top', 'padding-right', 'padding-bottom', 'padding-left' ); +$GLOBALS['csstidy']['shorthands']['-moz-border-radius'] = 0; + +/** + * All CSS Properties. Needed for csstidy::property_is_next() + * + * @global array $GLOBALS['csstidy']['all_properties'] + * @todo Add CSS3 properties + * @version 1.0 + * @see csstidy::property_is_next() + */ +$GLOBALS['csstidy']['all_properties']['align-content'] = 'CSS3.0'; +$GLOBALS['csstidy']['all_properties']['align-items'] = 'CSS3.0'; +$GLOBALS['csstidy']['all_properties']['align-self'] = 'CSS3.0'; +$GLOBALS['csstidy']['all_properties']['alignment-adjust'] = 'CSS3.0'; +$GLOBALS['csstidy']['all_properties']['alignment-baseline'] = 'CSS3.0'; +$GLOBALS['csstidy']['all_properties']['animation'] = 'CSS3.0'; +$GLOBALS['csstidy']['all_properties']['animation-delay'] = 'CSS3.0'; +$GLOBALS['csstidy']['all_properties']['animation-direction'] = 'CSS3.0'; +$GLOBALS['csstidy']['all_properties']['animation-duration'] = 'CSS3.0'; +$GLOBALS['csstidy']['all_properties']['animation-fill-mode'] = 'CSS3.0'; +$GLOBALS['csstidy']['all_properties']['animation-iteration-count'] = 'CSS3.0'; +$GLOBALS['csstidy']['all_properties']['animation-name'] = 'CSS3.0'; +$GLOBALS['csstidy']['all_properties']['animation-play-state'] = 'CSS3.0'; +$GLOBALS['csstidy']['all_properties']['animation-timing-function'] = 'CSS3.0'; +$GLOBALS['csstidy']['all_properties']['appearance'] = 'CSS3.0'; +$GLOBALS['csstidy']['all_properties']['azimuth'] = 'CSS2.0,CSS2.1,CSS3.0'; +$GLOBALS['csstidy']['all_properties']['backface-visibility'] = 'CSS3.0'; +$GLOBALS['csstidy']['all_properties']['background'] = 'CSS1.0,CSS2.0,CSS2.1,CSS3.0'; +$GLOBALS['csstidy']['all_properties']['background-attachment'] = 'CSS1.0,CSS2.0,CSS2.1,CSS3.0'; +$GLOBALS['csstidy']['all_properties']['background-clip'] = 'CSS3.0'; +$GLOBALS['csstidy']['all_properties']['background-color'] = 'CSS1.0,CSS2.0,CSS2.1,CSS3.0'; +$GLOBALS['csstidy']['all_properties']['background-image'] = 'CSS1.0,CSS2.0,CSS2.1,CSS3.0'; +$GLOBALS['csstidy']['all_properties']['background-origin'] = 'CSS3.0'; +$GLOBALS['csstidy']['all_properties']['background-position'] = 'CSS1.0,CSS2.0,CSS2.1,CSS3.0'; +$GLOBALS['csstidy']['all_properties']['background-repeat'] = 'CSS1.0,CSS2.0,CSS2.1,CSS3.0'; +$GLOBALS['csstidy']['all_properties']['background-size'] = 'CSS3.0'; +$GLOBALS['csstidy']['all_properties']['baseline-shift'] = 'CSS3.0'; +$GLOBALS['csstidy']['all_properties']['binding'] = 'CSS3.0'; +$GLOBALS['csstidy']['all_properties']['bleed'] = 'CSS3.0'; +$GLOBALS['csstidy']['all_properties']['bookmark-label'] = 'CSS3.0'; +$GLOBALS['csstidy']['all_properties']['bookmark-level'] = 'CSS3.0'; +$GLOBALS['csstidy']['all_properties']['bookmark-state'] = 'CSS3.0'; +$GLOBALS['csstidy']['all_properties']['bookmark-target'] = 'CSS3.0'; +$GLOBALS['csstidy']['all_properties']['border'] = 'CSS1.0,CSS2.0,CSS2.1,CSS3.0'; +$GLOBALS['csstidy']['all_properties']['border-bottom'] = 'CSS1.0,CSS2.0,CSS2.1,CSS3.0'; +$GLOBALS['csstidy']['all_properties']['border-bottom-color'] = 'CSS2.0,CSS2.1,CSS3.0'; +$GLOBALS['csstidy']['all_properties']['border-bottom-left-radius'] = 'CSS3.0'; +$GLOBALS['csstidy']['all_properties']['border-bottom-right-radius'] = 'CSS3.0'; +$GLOBALS['csstidy']['all_properties']['border-bottom-style'] = 'CSS2.0,CSS2.1,CSS3.0'; +$GLOBALS['csstidy']['all_properties']['border-bottom-width'] = 'CSS1.0,CSS2.0,CSS2.1,CSS3.0'; +$GLOBALS['csstidy']['all_properties']['border-collapse'] = 'CSS2.0,CSS2.1,CSS3.0'; +$GLOBALS['csstidy']['all_properties']['border-color'] = 'CSS1.0,CSS2.0,CSS2.1,CSS3.0'; +$GLOBALS['csstidy']['all_properties']['border-image'] = 'CSS3.0'; +$GLOBALS['csstidy']['all_properties']['border-image-outset'] = 'CSS3.0'; +$GLOBALS['csstidy']['all_properties']['border-image-repeat'] = 'CSS3.0'; +$GLOBALS['csstidy']['all_properties']['border-image-slice'] = 'CSS3.0'; +$GLOBALS['csstidy']['all_properties']['border-image-source'] = 'CSS3.0'; +$GLOBALS['csstidy']['all_properties']['border-image-width'] = 'CSS3.0'; +$GLOBALS['csstidy']['all_properties']['border-left'] = 'CSS1.0,CSS2.0,CSS2.1,CSS3.0'; +$GLOBALS['csstidy']['all_properties']['border-left-color'] = 'CSS2.0,CSS2.1,CSS3.0'; +$GLOBALS['csstidy']['all_properties']['border-left-style'] = 'CSS2.0,CSS2.1,CSS3.0'; +$GLOBALS['csstidy']['all_properties']['border-left-width'] = 'CSS1.0,CSS2.0,CSS2.1,CSS3.0'; +$GLOBALS['csstidy']['all_properties']['border-radius'] = 'CSS3.0'; +$GLOBALS['csstidy']['all_properties']['border-right'] = 'CSS1.0,CSS2.0,CSS2.1,CSS3.0'; +$GLOBALS['csstidy']['all_properties']['border-right-color'] = 'CSS2.0,CSS2.1,CSS3.0'; +$GLOBALS['csstidy']['all_properties']['border-right-style'] = 'CSS2.0,CSS2.1,CSS3.0'; +$GLOBALS['csstidy']['all_properties']['border-right-width'] = 'CSS1.0,CSS2.0,CSS2.1,CSS3.0'; +$GLOBALS['csstidy']['all_properties']['border-spacing'] = 'CSS2.0,CSS2.1,CSS3.0'; +$GLOBALS['csstidy']['all_properties']['border-style'] = 'CSS1.0,CSS2.0,CSS2.1,CSS3.0'; +$GLOBALS['csstidy']['all_properties']['border-top'] = 'CSS1.0,CSS2.0,CSS2.1,CSS3.0'; +$GLOBALS['csstidy']['all_properties']['border-top-color'] = 'CSS2.0,CSS2.1,CSS3.0'; +$GLOBALS['csstidy']['all_properties']['border-top-left-radius'] = 'CSS3.0'; +$GLOBALS['csstidy']['all_properties']['border-top-right-radius'] = 'CSS3.0'; +$GLOBALS['csstidy']['all_properties']['border-top-style'] = 'CSS2.0,CSS2.1,CSS3.0'; +$GLOBALS['csstidy']['all_properties']['border-top-width'] = 'CSS1.0,CSS2.0,CSS2.1,CSS3.0'; +$GLOBALS['csstidy']['all_properties']['border-width'] = 'CSS1.0,CSS2.0,CSS2.1,CSS3.0'; +$GLOBALS['csstidy']['all_properties']['bottom'] = 'CSS2.0,CSS2.1,CSS3.0'; +$GLOBALS['csstidy']['all_properties']['box-decoration-break'] = 'CSS3.0'; +$GLOBALS['csstidy']['all_properties']['box-shadow'] = 'CSS3.0'; +$GLOBALS['csstidy']['all_properties']['box-sizing'] = 'CSS3.0'; +$GLOBALS['csstidy']['all_properties']['break-after'] = 'CSS3.0'; +$GLOBALS['csstidy']['all_properties']['break-before'] = 'CSS3.0'; +$GLOBALS['csstidy']['all_properties']['break-inside'] = 'CSS3.0'; +$GLOBALS['csstidy']['all_properties']['caption-side'] = 'CSS2.0,CSS2.1,CSS3.0'; +$GLOBALS['csstidy']['all_properties']['clear'] = 'CSS1.0,CSS2.0,CSS2.1,CSS3.0'; +$GLOBALS['csstidy']['all_properties']['clip'] = 'CSS2.0,CSS2.1,CSS3.0'; +$GLOBALS['csstidy']['all_properties']['clip-path'] = 'CSS2.0,CSS2.1,CSS3.0'; +$GLOBALS['csstidy']['all_properties']['color'] = 'CSS1.0,CSS2.0,CSS2.1,CSS3.0'; +$GLOBALS['csstidy']['all_properties']['color-profile'] = 'CSS3.0'; +$GLOBALS['csstidy']['all_properties']['column-count'] = 'CSS3.0'; +$GLOBALS['csstidy']['all_properties']['column-fill'] = 'CSS3.0'; +$GLOBALS['csstidy']['all_properties']['column-gap'] = 'CSS3.0'; +$GLOBALS['csstidy']['all_properties']['column-rule'] = 'CSS3.0'; +$GLOBALS['csstidy']['all_properties']['column-rule-color'] = 'CSS3.0'; +$GLOBALS['csstidy']['all_properties']['column-rule-style'] = 'CSS3.0'; +$GLOBALS['csstidy']['all_properties']['column-rule-width'] = 'CSS3.0'; +$GLOBALS['csstidy']['all_properties']['column-span'] = 'CSS3.0'; +$GLOBALS['csstidy']['all_properties']['column-width'] = 'CSS3.0'; +$GLOBALS['csstidy']['all_properties']['columns'] = 'CSS3.0'; +$GLOBALS['csstidy']['all_properties']['content'] = 'CSS2.0,CSS2.1,CSS3.0'; +$GLOBALS['csstidy']['all_properties']['counter-increment'] = 'CSS2.0,CSS2.1,CSS3.0'; +$GLOBALS['csstidy']['all_properties']['counter-reset'] = 'CSS2.0,CSS2.1,CSS3.0'; +$GLOBALS['csstidy']['all_properties']['crop'] = 'CSS3.0'; +$GLOBALS['csstidy']['all_properties']['cue'] = 'CSS2.0,CSS2.1,CSS3.0'; +$GLOBALS['csstidy']['all_properties']['cue-after'] = 'CSS2.0,CSS2.1,CSS3.0'; +$GLOBALS['csstidy']['all_properties']['cue-before'] = 'CSS2.0,CSS2.1,CSS3.0'; +$GLOBALS['csstidy']['all_properties']['cursor'] = 'CSS2.0,CSS2.1,CSS3.0'; +$GLOBALS['csstidy']['all_properties']['direction'] = 'CSS2.0,CSS2.1,CSS3.0'; +$GLOBALS['csstidy']['all_properties']['display'] = 'CSS1.0,CSS2.0,CSS2.1,CSS3.0'; +$GLOBALS['csstidy']['all_properties']['dominant-baseline'] = 'CSS3.0'; +$GLOBALS['csstidy']['all_properties']['drop-initial-after-adjust'] = 'CSS3.0'; +$GLOBALS['csstidy']['all_properties']['drop-initial-after-align'] = 'CSS3.0'; +$GLOBALS['csstidy']['all_properties']['drop-initial-before-adjust'] = 'CSS3.0'; +$GLOBALS['csstidy']['all_properties']['drop-initial-before-align'] = 'CSS3.0'; +$GLOBALS['csstidy']['all_properties']['drop-initial-size'] = 'CSS3.0'; +$GLOBALS['csstidy']['all_properties']['drop-initial-value'] = 'CSS3.0'; +$GLOBALS['csstidy']['all_properties']['elevation'] = 'CSS2.0,CSS2.1,CSS3.0'; +$GLOBALS['csstidy']['all_properties']['empty-cells'] = 'CSS2.0,CSS2.1,CSS3.0'; +$GLOBALS['csstidy']['all_properties']['fill'] = 'CSS3.0'; +$GLOBALS['csstidy']['all_properties']['fit'] = 'CSS3.0'; +$GLOBALS['csstidy']['all_properties']['fit-position'] = 'CSS3.0'; +$GLOBALS['csstidy']['all_properties']['flex'] = 'CSS3.0'; +$GLOBALS['csstidy']['all_properties']['flex-align'] = 'CSS3.0'; +$GLOBALS['csstidy']['all_properties']['flex-basis'] = 'CSS3.0'; +$GLOBALS['csstidy']['all_properties']['flex-direction'] = 'CSS3.0'; +$GLOBALS['csstidy']['all_properties']['flex-flow'] = 'CSS3.0'; +$GLOBALS['csstidy']['all_properties']['flex-grow'] = 'CSS3.0'; +$GLOBALS['csstidy']['all_properties']['flex-line-pack'] = 'CSS3.0'; +$GLOBALS['csstidy']['all_properties']['flex-order'] = 'CSS3.0'; +$GLOBALS['csstidy']['all_properties']['flex-pack'] = 'CSS3.0'; +$GLOBALS['csstidy']['all_properties']['flex-shrink'] = 'CSS3.0'; +$GLOBALS['csstidy']['all_properties']['flex-wrap'] = 'CSS3.0'; +$GLOBALS['csstidy']['all_properties']['float'] = 'CSS1.0,CSS2.0,CSS2.1,CSS3.0'; +$GLOBALS['csstidy']['all_properties']['float-offset'] = 'CSS3.0'; +$GLOBALS['csstidy']['all_properties']['font'] = 'CSS1.0,CSS2.0,CSS2.1,CSS3.0'; +$GLOBALS['csstidy']['all_properties']['font-family'] = 'CSS1.0,CSS2.0,CSS2.1,CSS3.0'; +$GLOBALS['csstidy']['all_properties']['font-size'] = 'CSS1.0,CSS2.0,CSS2.1,CSS3.0'; +$GLOBALS['csstidy']['all_properties']['font-size-adjust'] = 'CSS2.0,CSS3.0'; +$GLOBALS['csstidy']['all_properties']['font-stretch'] = 'CSS2.0,CSS3.0'; +$GLOBALS['csstidy']['all_properties']['font-style'] = 'CSS1.0,CSS2.0,CSS2.1,CSS3.0'; +$GLOBALS['csstidy']['all_properties']['font-variant'] = 'CSS1.0,CSS2.0,CSS2.1,CSS3.0'; +$GLOBALS['csstidy']['all_properties']['font-weight'] = 'CSS1.0,CSS2.0,CSS2.1,CSS3.0'; +$GLOBALS['csstidy']['all_properties']['grid'] = 'CSS3.0'; +$GLOBALS['csstidy']['all_properties']['grid-area'] = 'CSS3.0'; +$GLOBALS['csstidy']['all_properties']['grid-auto-columns'] = 'CSS3.0'; +$GLOBALS['csstidy']['all_properties']['grid-auto-flow'] = 'CSS3.0'; +$GLOBALS['csstidy']['all_properties']['grid-auto-rows'] = 'CSS3.0'; +$GLOBALS['csstidy']['all_properties']['grid-column'] = 'CSS3.0'; +$GLOBALS['csstidy']['all_properties']['grid-columns'] = 'CSS3.0'; +$GLOBALS['csstidy']['all_properties']['grid-column-end'] = 'CSS3.0'; +$GLOBALS['csstidy']['all_properties']['grid-column-gap'] = 'CSS3.0'; +$GLOBALS['csstidy']['all_properties']['grid-column-start'] = 'CSS3.0'; +$GLOBALS['csstidy']['all_properties']['grid-gap'] = 'CSS3.0'; +$GLOBALS['csstidy']['all_properties']['grid-row'] = 'CSS3.0'; +$GLOBALS['csstidy']['all_properties']['grid-rows'] = 'CSS3.0'; +$GLOBALS['csstidy']['all_properties']['grid-row-end'] = 'CSS3.0'; +$GLOBALS['csstidy']['all_properties']['grid-row-gap'] = 'CSS3.0'; +$GLOBALS['csstidy']['all_properties']['grid-row-start'] = 'CSS3.0'; +$GLOBALS['csstidy']['all_properties']['grid-template'] = 'CSS3.0'; +$GLOBALS['csstidy']['all_properties']['grid-template-areas'] = 'CSS3.0'; +$GLOBALS['csstidy']['all_properties']['grid-template-columns'] = 'CSS3.0'; +$GLOBALS['csstidy']['all_properties']['grid-template-rows'] = 'CSS3.0'; +$GLOBALS['csstidy']['all_properties']['hanging-punctuation'] = 'CSS3.0'; +$GLOBALS['csstidy']['all_properties']['height'] = 'CSS1.0,CSS2.0,CSS2.1,CSS3.0'; +$GLOBALS['csstidy']['all_properties']['hyphenate-after'] = 'CSS3.0'; +$GLOBALS['csstidy']['all_properties']['hyphenate-before'] = 'CSS3.0'; +$GLOBALS['csstidy']['all_properties']['hyphenate-character'] = 'CSS3.0'; +$GLOBALS['csstidy']['all_properties']['hyphenate-lines'] = 'CSS3.0'; +$GLOBALS['csstidy']['all_properties']['hyphenate-resource'] = 'CSS3.0'; +$GLOBALS['csstidy']['all_properties']['hyphens'] = 'CSS3.0'; +$GLOBALS['csstidy']['all_properties']['icon'] = 'CSS3.0'; +$GLOBALS['csstidy']['all_properties']['image-orientation'] = 'CSS3.0'; +$GLOBALS['csstidy']['all_properties']['image-rendering'] = 'CSS3.0'; +$GLOBALS['csstidy']['all_properties']['image-resolution'] = 'CSS3.0'; +$GLOBALS['csstidy']['all_properties']['inline-box-align'] = 'CSS3.0'; +$GLOBALS['csstidy']['all_properties']['justify-content'] = 'CSS3.0'; +$GLOBALS['csstidy']['all_properties']['justify-items'] = 'CSS3.0'; +$GLOBALS['csstidy']['all_properties']['justify-self'] = 'CSS3.0'; +$GLOBALS['csstidy']['all_properties']['left'] = 'CSS2.0,CSS2.1,CSS3.0'; +$GLOBALS['csstidy']['all_properties']['letter-spacing'] = 'CSS1.0,CSS2.0,CSS2.1,CSS3.0'; +$GLOBALS['csstidy']['all_properties']['line-break'] = 'CSS3.0'; +$GLOBALS['csstidy']['all_properties']['line-height'] = 'CSS1.0,CSS2.0,CSS2.1,CSS3.0'; +$GLOBALS['csstidy']['all_properties']['line-stacking'] = 'CSS3.0'; +$GLOBALS['csstidy']['all_properties']['line-stacking-ruby'] = 'CSS3.0'; +$GLOBALS['csstidy']['all_properties']['line-stacking-shift'] = 'CSS3.0'; +$GLOBALS['csstidy']['all_properties']['line-stacking-strategy'] = 'CSS3.0'; +$GLOBALS['csstidy']['all_properties']['list-style'] = 'CSS1.0,CSS2.0,CSS2.1,CSS3.0'; +$GLOBALS['csstidy']['all_properties']['list-style-image'] = 'CSS1.0,CSS2.0,CSS2.1,CSS3.0'; +$GLOBALS['csstidy']['all_properties']['list-style-position'] = 'CSS1.0,CSS2.0,CSS2.1,CSS3.0'; +$GLOBALS['csstidy']['all_properties']['list-style-type'] = 'CSS1.0,CSS2.0,CSS2.1,CSS3.0'; +$GLOBALS['csstidy']['all_properties']['margin'] = 'CSS1.0,CSS2.0,CSS2.1,CSS3.0'; +$GLOBALS['csstidy']['all_properties']['margin-bottom'] = 'CSS1.0,CSS2.0,CSS2.1,CSS3.0'; +$GLOBALS['csstidy']['all_properties']['margin-left'] = 'CSS1.0,CSS2.0,CSS2.1,CSS3.0'; +$GLOBALS['csstidy']['all_properties']['margin-right'] = 'CSS1.0,CSS2.0,CSS2.1,CSS3.0'; +$GLOBALS['csstidy']['all_properties']['margin-top'] = 'CSS1.0,CSS2.0,CSS2.1,CSS3.0'; +$GLOBALS['csstidy']['all_properties']['marker-offset'] = 'CSS3.0'; +$GLOBALS['csstidy']['all_properties']['marks'] = 'CSS2.0,CSS3.0'; +$GLOBALS['csstidy']['all_properties']['marquee-direction'] = 'CSS3.0'; +$GLOBALS['csstidy']['all_properties']['marquee-loop'] = 'CSS3.0'; +$GLOBALS['csstidy']['all_properties']['marquee-play-count'] = 'CSS3.0'; +$GLOBALS['csstidy']['all_properties']['marquee-speed'] = 'CSS3.0'; +$GLOBALS['csstidy']['all_properties']['marquee-style'] = 'CSS3.0'; +$GLOBALS['csstidy']['all_properties']['mask-clip'] = 'CSS3.0'; +$GLOBALS['csstidy']['all_properties']['mask-composite'] = 'CSS3.0'; +$GLOBALS['csstidy']['all_properties']['mask-image'] = 'CSS3.0'; +$GLOBALS['csstidy']['all_properties']['mask-mode'] = 'CSS3.0'; +$GLOBALS['csstidy']['all_properties']['mask-origin'] = 'CSS3.0'; +$GLOBALS['csstidy']['all_properties']['mask-position'] = 'CSS3.0'; +$GLOBALS['csstidy']['all_properties']['mask-repeat'] = 'CSS3.0'; +$GLOBALS['csstidy']['all_properties']['mask-size'] = 'CSS3.0'; +$GLOBALS['csstidy']['all_properties']['max-height'] = 'CSS2.0,CSS2.1,CSS3.0'; +$GLOBALS['csstidy']['all_properties']['max-width'] = 'CSS2.0,CSS2.1,CSS3.0'; +$GLOBALS['csstidy']['all_properties']['min-height'] = 'CSS2.0,CSS2.1,CSS3.0'; +$GLOBALS['csstidy']['all_properties']['min-width'] = 'CSS2.0,CSS2.1,CSS3.0'; +$GLOBALS['csstidy']['all_properties']['move-to'] = 'CSS3.0'; +$GLOBALS['csstidy']['all_properties']['nav-down'] = 'CSS3.0'; +$GLOBALS['csstidy']['all_properties']['nav-index'] = 'CSS3.0'; +$GLOBALS['csstidy']['all_properties']['nav-left'] = 'CSS3.0'; +$GLOBALS['csstidy']['all_properties']['nav-right'] = 'CSS3.0'; +$GLOBALS['csstidy']['all_properties']['nav-up'] = 'CSS3.0'; +$GLOBALS['csstidy']['all_properties']['object-fit'] = 'CSS3.0'; +$GLOBALS['csstidy']['all_properties']['object-position'] = 'CSS3.0'; +$GLOBALS['csstidy']['all_properties']['opacity'] = 'CSS3.0'; +$GLOBALS['csstidy']['all_properties']['order'] = 'CSS3.0'; +$GLOBALS['csstidy']['all_properties']['orphans'] = 'CSS2.0,CSS2.1,CSS3.0'; +$GLOBALS['csstidy']['all_properties']['outline'] = 'CSS2.0,CSS2.1,CSS3.0'; +$GLOBALS['csstidy']['all_properties']['outline-color'] = 'CSS2.0,CSS2.1,CSS3.0'; +$GLOBALS['csstidy']['all_properties']['outline-offset'] = 'CSS3.0'; +$GLOBALS['csstidy']['all_properties']['outline-style'] = 'CSS2.0,CSS2.1,CSS3.0'; +$GLOBALS['csstidy']['all_properties']['outline-width'] = 'CSS2.0,CSS2.1,CSS3.0'; +$GLOBALS['csstidy']['all_properties']['overflow'] = 'CSS2.0,CSS2.1,CSS3.0'; +$GLOBALS['csstidy']['all_properties']['overflow-style'] = 'CSS3.0'; +$GLOBALS['csstidy']['all_properties']['overflow-wrap'] = 'CSS3.0'; +$GLOBALS['csstidy']['all_properties']['overflow-x'] = 'CSS3.0'; +$GLOBALS['csstidy']['all_properties']['overflow-y'] = 'CSS3.0'; +$GLOBALS['csstidy']['all_properties']['padding'] = 'CSS1.0,CSS2.0,CSS2.1,CSS3.0'; +$GLOBALS['csstidy']['all_properties']['padding-bottom'] = 'CSS1.0,CSS2.0,CSS2.1,CSS3.0'; +$GLOBALS['csstidy']['all_properties']['padding-left'] = 'CSS1.0,CSS2.0,CSS2.1,CSS3.0'; +$GLOBALS['csstidy']['all_properties']['padding-right'] = 'CSS1.0,CSS2.0,CSS2.1,CSS3.0'; +$GLOBALS['csstidy']['all_properties']['padding-top'] = 'CSS1.0,CSS2.0,CSS2.1,CSS3.0'; +$GLOBALS['csstidy']['all_properties']['page'] = 'CSS2.0,CSS3.0'; +$GLOBALS['csstidy']['all_properties']['page-break-after'] = 'CSS2.0,CSS2.1,CSS3.0'; +$GLOBALS['csstidy']['all_properties']['page-break-before'] = 'CSS2.0,CSS2.1,CSS3.0'; +$GLOBALS['csstidy']['all_properties']['page-break-inside'] = 'CSS2.0,CSS2.1,CSS3.0'; +$GLOBALS['csstidy']['all_properties']['page-policy'] = 'CSS3.0'; +$GLOBALS['csstidy']['all_properties']['pause'] = 'CSS2.0,CSS2.1,CSS3.0'; +$GLOBALS['csstidy']['all_properties']['pause-after'] = 'CSS2.0,CSS2.1,CSS3.0'; +$GLOBALS['csstidy']['all_properties']['pause-before'] = 'CSS2.0,CSS2.1,CSS3.0'; +$GLOBALS['csstidy']['all_properties']['perspective'] = 'CSS3.0'; +$GLOBALS['csstidy']['all_properties']['perspective-origin'] = 'CSS3.0'; +$GLOBALS['csstidy']['all_properties']['phonemes'] = 'CSS3.0'; +$GLOBALS['csstidy']['all_properties']['pitch'] = 'CSS2.0,CSS2.1,CSS3.0'; +$GLOBALS['csstidy']['all_properties']['pitch-range'] = 'CSS2.0,CSS2.1,CSS3.0'; +$GLOBALS['csstidy']['all_properties']['play-during'] = 'CSS2.0,CSS2.1,CSS3.0'; +$GLOBALS['csstidy']['all_properties']['position'] = 'CSS2.0,CSS2.1,CSS3.0'; +$GLOBALS['csstidy']['all_properties']['presentation-level'] = 'CSS3.0'; +$GLOBALS['csstidy']['all_properties']['punctuation-trim'] = 'CSS3.0'; +$GLOBALS['csstidy']['all_properties']['quotes'] = 'CSS2.0,CSS2.1,CSS3.0'; +$GLOBALS['csstidy']['all_properties']['rendering-intent'] = 'CSS3.0'; +$GLOBALS['csstidy']['all_properties']['resize'] = 'CSS3.0'; +$GLOBALS['csstidy']['all_properties']['rest'] = 'CSS3.0'; +$GLOBALS['csstidy']['all_properties']['rest-after'] = 'CSS3.0'; +$GLOBALS['csstidy']['all_properties']['rest-before'] = 'CSS3.0'; +$GLOBALS['csstidy']['all_properties']['richness'] = 'CSS2.0,CSS2.1,CSS3.0'; +$GLOBALS['csstidy']['all_properties']['right'] = 'CSS2.0,CSS2.1,CSS3.0'; +$GLOBALS['csstidy']['all_properties']['rotation'] = 'CSS3.0'; +$GLOBALS['csstidy']['all_properties']['rotation-point'] = 'CSS3.0'; +$GLOBALS['csstidy']['all_properties']['ruby-align'] = 'CSS3.0'; +$GLOBALS['csstidy']['all_properties']['ruby-overhang'] = 'CSS3.0'; +$GLOBALS['csstidy']['all_properties']['ruby-position'] = 'CSS3.0'; +$GLOBALS['csstidy']['all_properties']['ruby-span'] = 'CSS3.0'; +$GLOBALS['csstidy']['all_properties']['scroll-behavior'] = 'CSS3.0'; +$GLOBALS['csstidy']['all_properties']['scroll-margin'] = 'CSS3.0'; +$GLOBALS['csstidy']['all_properties']['scroll-margin-block'] = 'CSS3.0'; +$GLOBALS['csstidy']['all_properties']['scroll-margin-block-end'] = 'CSS3.0'; +$GLOBALS['csstidy']['all_properties']['scroll-margin-block-start'] = 'CSS3.0'; +$GLOBALS['csstidy']['all_properties']['scroll-margin-bottom'] = 'CSS3.0'; +$GLOBALS['csstidy']['all_properties']['scroll-margin-inline'] = 'CSS3.0'; +$GLOBALS['csstidy']['all_properties']['scroll-margin-inline-end'] = 'CSS3.0'; +$GLOBALS['csstidy']['all_properties']['scroll-margin-inline-start'] = 'CSS3.0'; +$GLOBALS['csstidy']['all_properties']['scroll-margin-left'] = 'CSS3.0'; +$GLOBALS['csstidy']['all_properties']['scroll-margin-right'] = 'CSS3.0'; +$GLOBALS['csstidy']['all_properties']['scroll-margin-top'] = 'CSS3.0'; +$GLOBALS['csstidy']['all_properties']['scroll-padding'] = 'CSS3.0'; +$GLOBALS['csstidy']['all_properties']['scroll-padding-block'] = 'CSS3.0'; +$GLOBALS['csstidy']['all_properties']['scroll-padding-block-end'] = 'CSS3.0'; +$GLOBALS['csstidy']['all_properties']['scroll-padding-block-start'] = 'CSS3.0'; +$GLOBALS['csstidy']['all_properties']['scroll-padding-bottom'] = 'CSS3.0'; +$GLOBALS['csstidy']['all_properties']['scroll-padding-inline'] = 'CSS3.0'; +$GLOBALS['csstidy']['all_properties']['scroll-padding-inline-end'] = 'CSS3.0'; +$GLOBALS['csstidy']['all_properties']['scroll-padding-inline-start'] = 'CSS3.0'; +$GLOBALS['csstidy']['all_properties']['scroll-padding-left'] = 'CSS3.0'; +$GLOBALS['csstidy']['all_properties']['scroll-padding-right'] = 'CSS3.0'; +$GLOBALS['csstidy']['all_properties']['scroll-padding-top'] = 'CSS3.0'; +$GLOBALS['csstidy']['all_properties']['scroll-snap-align'] = 'CSS3.0'; +$GLOBALS['csstidy']['all_properties']['scroll-snap-stop'] = 'CSS3.0'; +$GLOBALS['csstidy']['all_properties']['size'] = 'CSS2.0,CSS3.0'; +$GLOBALS['csstidy']['all_properties']['speak'] = 'CSS2.0,CSS2.1,CSS3.0'; +$GLOBALS['csstidy']['all_properties']['speak-header'] = 'CSS2.0,CSS2.1,CSS3.0'; +$GLOBALS['csstidy']['all_properties']['speak-numeral'] = 'CSS2.0,CSS2.1,CSS3.0'; +$GLOBALS['csstidy']['all_properties']['speak-punctuation'] = 'CSS2.0,CSS2.1,CSS3.0'; +$GLOBALS['csstidy']['all_properties']['speech-rate'] = 'CSS2.0,CSS2.1,CSS3.0'; +$GLOBALS['csstidy']['all_properties']['src'] = 'CSS3.0'; +$GLOBALS['csstidy']['all_properties']['stress'] = 'CSS2.0,CSS2.1,CSS3.0'; +$GLOBALS['csstidy']['all_properties']['string-set'] = 'CSS3.0'; +$GLOBALS['csstidy']['all_properties']['stroke'] = 'CSS3.0'; +$GLOBALS['csstidy']['all_properties']['tab-size'] = 'CSS3.0'; +$GLOBALS['csstidy']['all_properties']['table-layout'] = 'CSS2.0,CSS2.1,CSS3.0'; +$GLOBALS['csstidy']['all_properties']['target'] = 'CSS3.0'; +$GLOBALS['csstidy']['all_properties']['target-name'] = 'CSS3.0'; +$GLOBALS['csstidy']['all_properties']['target-new'] = 'CSS3.0'; +$GLOBALS['csstidy']['all_properties']['target-position'] = 'CSS3.0'; +$GLOBALS['csstidy']['all_properties']['text-align'] = 'CSS1.0,CSS2.0,CSS2.1,CSS3.0'; +$GLOBALS['csstidy']['all_properties']['text-align-last'] = 'CSS3.0'; +$GLOBALS['csstidy']['all_properties']['text-decoration'] = 'CSS1.0,CSS2.0,CSS2.1,CSS3.0'; +$GLOBALS['csstidy']['all_properties']['text-decoration-color'] = 'CSS3.0'; +$GLOBALS['csstidy']['all_properties']['text-decoration-line'] = 'CSS3.0'; +$GLOBALS['csstidy']['all_properties']['text-decoration-skip'] = 'CSS3.0'; +$GLOBALS['csstidy']['all_properties']['text-decoration-style'] = 'CSS3.0'; +$GLOBALS['csstidy']['all_properties']['text-emphasis'] = 'CSS3.0'; +$GLOBALS['csstidy']['all_properties']['text-emphasis-color'] = 'CSS3.0'; +$GLOBALS['csstidy']['all_properties']['text-emphasis-position'] = 'CSS3.0'; +$GLOBALS['csstidy']['all_properties']['text-emphasis-style'] = 'CSS3.0'; +$GLOBALS['csstidy']['all_properties']['text-height'] = 'CSS3.0'; +$GLOBALS['csstidy']['all_properties']['text-indent'] = 'CSS1.0,CSS2.0,CSS2.1,CSS3.0'; +$GLOBALS['csstidy']['all_properties']['text-justify'] = 'CSS3.0'; +$GLOBALS['csstidy']['all_properties']['text-outline'] = 'CSS3.0'; +$GLOBALS['csstidy']['all_properties']['text-shadow'] = 'CSS2.0,CSS3.0'; +$GLOBALS['csstidy']['all_properties']['text-space-collapse'] = 'CSS3.0'; +$GLOBALS['csstidy']['all_properties']['text-transform'] = 'CSS1.0,CSS2.0,CSS2.1,CSS3.0'; +$GLOBALS['csstidy']['all_properties']['text-underline-position'] = 'CSS3.0'; +$GLOBALS['csstidy']['all_properties']['text-wrap'] = 'CSS3.0'; +$GLOBALS['csstidy']['all_properties']['top'] = 'CSS2.0,CSS2.1,CSS3.0'; +$GLOBALS['csstidy']['all_properties']['transform'] = 'CSS3.0'; +$GLOBALS['csstidy']['all_properties']['transform-origin'] = 'CSS3.0'; +$GLOBALS['csstidy']['all_properties']['transform-style'] = 'CSS3.0'; +$GLOBALS['csstidy']['all_properties']['transition'] = 'CSS3.0'; +$GLOBALS['csstidy']['all_properties']['transition-delay'] = 'CSS3.0'; +$GLOBALS['csstidy']['all_properties']['transition-duration'] = 'CSS3.0'; +$GLOBALS['csstidy']['all_properties']['transition-property'] = 'CSS3.0'; +$GLOBALS['csstidy']['all_properties']['transition-timing-function'] = 'CSS3.0'; +$GLOBALS['csstidy']['all_properties']['unicode-bidi'] = 'CSS2.0,CSS2.1,CSS3.0'; +$GLOBALS['csstidy']['all_properties']['vertical-align'] = 'CSS1.0,CSS2.0,CSS2.1,CSS3.0'; +$GLOBALS['csstidy']['all_properties']['visibility'] = 'CSS2.0,CSS2.1,CSS3.0'; +$GLOBALS['csstidy']['all_properties']['voice-balance'] = 'CSS3.0'; +$GLOBALS['csstidy']['all_properties']['voice-duration'] = 'CSS3.0'; +$GLOBALS['csstidy']['all_properties']['voice-family'] = 'CSS2.0,CSS2.1,CSS3.0'; +$GLOBALS['csstidy']['all_properties']['voice-pitch'] = 'CSS3.0'; +$GLOBALS['csstidy']['all_properties']['voice-pitch-range'] = 'CSS3.0'; +$GLOBALS['csstidy']['all_properties']['voice-rate'] = 'CSS3.0'; +$GLOBALS['csstidy']['all_properties']['voice-stress'] = 'CSS3.0'; +$GLOBALS['csstidy']['all_properties']['voice-volume'] = 'CSS3.0'; +$GLOBALS['csstidy']['all_properties']['volume'] = 'CSS2.0,CSS2.1,CSS3.0'; +$GLOBALS['csstidy']['all_properties']['white-space'] = 'CSS1.0,CSS2.0,CSS2.1,CSS3.0'; +$GLOBALS['csstidy']['all_properties']['widows'] = 'CSS2.0,CSS2.1,CSS3.0'; +$GLOBALS['csstidy']['all_properties']['width'] = 'CSS1.0,CSS2.0,CSS2.1,CSS3.0'; +$GLOBALS['csstidy']['all_properties']['word-break'] = 'CSS3.0'; +$GLOBALS['csstidy']['all_properties']['word-spacing'] = 'CSS1.0,CSS2.0,CSS2.1,CSS3.0'; +$GLOBALS['csstidy']['all_properties']['word-wrap'] = 'CSS3.0'; +$GLOBALS['csstidy']['all_properties']['z-index'] = 'CSS2.0,CSS2.1,CSS3.0'; + +/** + * An array containing all properties that can accept a quoted string as a value. + * + * @global array $GLOBALS['csstidy']['quoted_string_properties'] + */ +$GLOBALS['csstidy']['quoted_string_properties'] = array( 'content', 'font', 'font-family', 'quotes' ); + +/** + * An array containing all properties that can be defined multiple times without being overwritten. + * All unit values are included so that units like rem can be supported with fallbacks to px or em. + * + * @global array $GLOBALS['csstidy']['quoted_string_properties'] + */ +$GLOBALS['csstidy']['multiple_properties'] = array_merge( $GLOBALS['csstidy']['color_values'], $GLOBALS['csstidy']['unit_values'], array( 'transition', 'background-image', 'border-image', 'list-style-image' ) ); + +/** + * An array containing all predefined templates. + * + * @global array $GLOBALS['csstidy']['predefined_templates'] + * @version 1.0 + * @see csstidy::load_template() + */ +$GLOBALS['csstidy']['predefined_templates']['default'][] = '<span class="at">'; // string before @rule +$GLOBALS['csstidy']['predefined_templates']['default'][] = '</span> <span class="format">{</span>' . "\n"; // bracket after @-rule +$GLOBALS['csstidy']['predefined_templates']['default'][] = '<span class="selector">'; // string before selector +$GLOBALS['csstidy']['predefined_templates']['default'][] = '</span> <span class="format">{</span>' . "\n"; // bracket after selector +$GLOBALS['csstidy']['predefined_templates']['default'][] = '<span class="property">'; // string before property +$GLOBALS['csstidy']['predefined_templates']['default'][] = '</span><span class="value">'; // string after property+before value +$GLOBALS['csstidy']['predefined_templates']['default'][] = '</span><span class="format">;</span>' . "\n"; // string after value +$GLOBALS['csstidy']['predefined_templates']['default'][] = '<span class="format">}</span>'; // closing bracket - selector +$GLOBALS['csstidy']['predefined_templates']['default'][] = "\n\n"; // space between blocks {...} +$GLOBALS['csstidy']['predefined_templates']['default'][] = "\n" . '<span class="format">}</span>' . "\n\n"; // closing bracket @-rule +$GLOBALS['csstidy']['predefined_templates']['default'][] = ''; // indent in @-rule +$GLOBALS['csstidy']['predefined_templates']['default'][] = '<span class="comment">'; // before comment +$GLOBALS['csstidy']['predefined_templates']['default'][] = '</span>' . "\n"; // after comment +$GLOBALS['csstidy']['predefined_templates']['default'][] = "\n"; // after last line @-rule + +$GLOBALS['csstidy']['predefined_templates']['high_compression'][] = '<span class="at">'; +$GLOBALS['csstidy']['predefined_templates']['high_compression'][] = '</span> <span class="format">{</span>' . "\n"; +$GLOBALS['csstidy']['predefined_templates']['high_compression'][] = '<span class="selector">'; +$GLOBALS['csstidy']['predefined_templates']['high_compression'][] = '</span><span class="format">{</span>'; +$GLOBALS['csstidy']['predefined_templates']['high_compression'][] = '<span class="property">'; +$GLOBALS['csstidy']['predefined_templates']['high_compression'][] = '</span><span class="value">'; +$GLOBALS['csstidy']['predefined_templates']['high_compression'][] = '</span><span class="format">;</span>'; +$GLOBALS['csstidy']['predefined_templates']['high_compression'][] = '<span class="format">}</span>'; +$GLOBALS['csstidy']['predefined_templates']['high_compression'][] = "\n"; +$GLOBALS['csstidy']['predefined_templates']['high_compression'][] = "\n" . '<span class="format">}' . "\n" . '</span>'; +$GLOBALS['csstidy']['predefined_templates']['high_compression'][] = ''; +$GLOBALS['csstidy']['predefined_templates']['high_compression'][] = '<span class="comment">'; // before comment +$GLOBALS['csstidy']['predefined_templates']['high_compression'][] = '</span>'; // after comment +$GLOBALS['csstidy']['predefined_templates']['high_compression'][] = "\n"; + +$GLOBALS['csstidy']['predefined_templates']['highest_compression'][] = '<span class="at">'; +$GLOBALS['csstidy']['predefined_templates']['highest_compression'][] = '</span><span class="format">{</span>'; +$GLOBALS['csstidy']['predefined_templates']['highest_compression'][] = '<span class="selector">'; +$GLOBALS['csstidy']['predefined_templates']['highest_compression'][] = '</span><span class="format">{</span>'; +$GLOBALS['csstidy']['predefined_templates']['highest_compression'][] = '<span class="property">'; +$GLOBALS['csstidy']['predefined_templates']['highest_compression'][] = '</span><span class="value">'; +$GLOBALS['csstidy']['predefined_templates']['highest_compression'][] = '</span><span class="format">;</span>'; +$GLOBALS['csstidy']['predefined_templates']['highest_compression'][] = '<span class="format">}</span>'; +$GLOBALS['csstidy']['predefined_templates']['highest_compression'][] = ''; +$GLOBALS['csstidy']['predefined_templates']['highest_compression'][] = '<span class="format">}</span>'; +$GLOBALS['csstidy']['predefined_templates']['highest_compression'][] = ''; +$GLOBALS['csstidy']['predefined_templates']['highest_compression'][] = '<span class="comment">'; // before comment +$GLOBALS['csstidy']['predefined_templates']['highest_compression'][] = '</span>'; // after comment +$GLOBALS['csstidy']['predefined_templates']['highest_compression'][] = ''; + +$GLOBALS['csstidy']['predefined_templates']['low_compression'][] = '<span class="at">'; +$GLOBALS['csstidy']['predefined_templates']['low_compression'][] = '</span> <span class="format">{</span>' . "\n"; +$GLOBALS['csstidy']['predefined_templates']['low_compression'][] = '<span class="selector">'; +$GLOBALS['csstidy']['predefined_templates']['low_compression'][] = '</span>' . "\n" . '<span class="format">{</span>' . "\n"; +$GLOBALS['csstidy']['predefined_templates']['low_compression'][] = ' <span class="property">'; +$GLOBALS['csstidy']['predefined_templates']['low_compression'][] = '</span><span class="value">'; +$GLOBALS['csstidy']['predefined_templates']['low_compression'][] = '</span><span class="format">;</span>' . "\n"; +$GLOBALS['csstidy']['predefined_templates']['low_compression'][] = '<span class="format">}</span>'; +$GLOBALS['csstidy']['predefined_templates']['low_compression'][] = "\n\n"; +$GLOBALS['csstidy']['predefined_templates']['low_compression'][] = "\n" . '<span class="format">}</span>' . "\n\n"; +$GLOBALS['csstidy']['predefined_templates']['low_compression'][] = ' '; +$GLOBALS['csstidy']['predefined_templates']['low_compression'][] = '<span class="comment">'; // before comment +$GLOBALS['csstidy']['predefined_templates']['low_compression'][] = '</span>' . "\n"; // after comment +$GLOBALS['csstidy']['predefined_templates']['low_compression'][] = "\n"; + +require __DIR__ . '/data-wp.inc.php'; diff --git a/csstidy/lang.inc.php b/csstidy/lang.inc.php new file mode 100644 index 0000000..08459f3 --- /dev/null +++ b/csstidy/lang.inc.php @@ -0,0 +1,303 @@ +<?php +/** + * Localization of CSS Optimiser Interface of CSSTidy + * + * Copyright 2005, 2006, 2007 Florian Schmitz + * + * This file is part of CSSTidy. + * + * CSSTidy is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1 of the License, or + * (at your option) any later version. + * + * CSSTidy is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + * + * @license https://opensource.org/licenses/lgpl-license.php GNU Lesser General Public License + * @package csstidy + * @author Florian Schmitz (floele at gmail dot com) 2005-2007, Brett Zamir (brettz9 at yahoo dot com) 2007 + */ + +if ( isset( $_GET['lang'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- no changes made to the site, determening language for translations. + $l = sanitize_text_field( wp_unslash( $_GET['lang'] ) ); // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- no changes made to the site, determining language for translations. +} elseif ( isset( $_SERVER['HTTP_ACCEPT_LANGUAGE'] ) ) { + $l = $_SERVER['HTTP_ACCEPT_LANGUAGE']; + $l = strtolower( substr( $l, 0, 2 ) ); +} else { + $l = ''; +} + +$l = ( in_array( $l, array( 'de', 'fr', 'zh' ), true ) ) ? $l : 'en'; + +// note 5 in all but French, and 40 in all are orphaned + +$lang = array(); +$lang['en'][0] = 'CSS Formatter and Optimiser/Optimizer (based on CSSTidy '; +$lang['en'][1] = 'CSS Formatter and Optimiser'; +$lang['en'][2] = '(based on'; +$lang['en'][3] = '(plaintext)'; +$lang['en'][4] = 'Important Note:'; +$lang['en'][6] = 'Your code should be well-formed. This is <strong>not a validator</strong> which points out errors in your CSS code. To make sure that your code is valid, use the <a href="https://jigsaw.w3.org/css-validator/">W3C Validator</a>.'; +$lang['en'][7] = 'all comments are removed'; +$lang['en'][8] = 'CSS Input:'; +$lang['en'][9] = 'CSS-Code:'; +$lang['en'][10] = 'CSS from URL:'; +$lang['en'][11] = 'Code Layout:'; +$lang['en'][12] = 'Compression (code layout):'; +$lang['en'][13] = 'Highest (no readability, smallest size)'; +$lang['en'][14] = 'High (moderate readability, smaller size)'; +$lang['en'][15] = 'Standard (balance between readability and size)'; +$lang['en'][16] = 'Low (higher readability)'; +$lang['en'][17] = 'Custom (enter below)'; +$lang['en'][18] = 'Custom <a href="http://csstidy.sourceforge.net/templates.php">template</a>'; +$lang['en'][19] = 'Options'; +$lang['en'][20] = 'Sort Selectors (caution)'; +$lang['en'][21] = 'Sort Properties'; +$lang['en'][22] = 'Regroup selectors'; +$lang['en'][23] = 'Optimise shorthands'; +$lang['en'][24] = 'Compress colors'; +$lang['en'][25] = 'Lowercase selectors'; +$lang['en'][26] = 'Case for properties:'; +$lang['en'][27] = 'Lowercase'; +$lang['en'][28] = 'No or invalid CSS input or wrong URL!'; +$lang['en'][29] = 'Uppercase'; +$lang['en'][30] = 'lowercase elementnames needed for XHTML'; +$lang['en'][31] = 'Remove unnecessary backslashes'; +$lang['en'][32] = 'convert !important-hack'; +$lang['en'][33] = 'Output as file'; +$lang['en'][34] = 'Bigger compression because of smaller newlines (copy & paste doesn\'t work)'; +$lang['en'][35] = 'Process CSS'; +$lang['en'][36] = 'Compression Ratio'; +$lang['en'][37] = 'Input'; +$lang['en'][38] = 'Output'; +$lang['en'][39] = 'Language'; +$lang['en'][41] = 'Attention: This may change the behavior of your CSS Code!'; +$lang['en'][42] = 'Remove last ;'; +$lang['en'][43] = 'Discard invalid properties'; +$lang['en'][44] = 'Only safe optimisations'; +$lang['en'][45] = 'Compress font-weight'; +$lang['en'][46] = 'Save comments'; +$lang['en'][47] = 'Do not change anything'; +$lang['en'][48] = 'Only separate selectors (split at ,)'; +$lang['en'][49] = 'Merge selectors with the same properties (fast)'; +$lang['en'][50] = 'Merge selectors intelligently (slow)'; +$lang['en'][51] = 'Preserve CSS'; +$lang['en'][52] = 'Save comments, hacks, etc. Most optimisations can *not* be applied if this is enabled.'; +$lang['en'][53] = 'None'; +$lang['en'][54] = 'Don\'t optimise'; +$lang['en'][55] = 'Safe optimisations'; +$lang['en'][56] = 'All optimisations'; +$lang['en'][57] = 'Add timestamp'; +$lang['en'][58] = 'Copy to clipboard'; +$lang['en'][59] = 'Back to top'; +$lang['en'][60] = 'Your browser doesn\'t support copy to clipboard.'; +$lang['en'][61] = 'For bugs and suggestions feel free to'; +$lang['en'][62] = 'contact me'; +$lang['en'][63] = 'Output CSS code as complete HTML document'; +$lang['en'][64] = 'Code'; +$lang['en'][65] = 'CSS to style CSS output'; +$lang['en'][66] = 'You need to go to about:config in your URL bar, select \'signed.applets.codebase_principal_support\' in the filter field, and set its value to true in order to use this feature; however, be aware that doing so increases security risks.'; + +$lang['de'][0] = 'CSS Formatierer und Optimierer (basierend auf CSSTidy '; +$lang['de'][1] = 'CSS Formatierer und Optimierer'; +$lang['de'][2] = '(basierend auf'; +$lang['de'][3] = '(Textversion)'; +$lang['de'][4] = 'Wichtiger Hinweis:'; +$lang['de'][6] = 'Der CSS Code sollte wohlgeformt sein. Der CSS Code wird <strong>nicht auf Gültigkeit überprüft</strong>. Um sicherzugehen dass dein Code valide ist, benutze den <a href="https://jigsaw.w3.org/css-validator/">W3C Validierungsservice</a>.'; +$lang['de'][7] = 'alle Kommentare werden entfernt'; +$lang['de'][8] = 'CSS Eingabe:'; +$lang['de'][9] = 'CSS-Code:'; +$lang['de'][10] = 'CSS von URL:'; +$lang['de'][11] = 'Code Layout:'; +$lang['de'][12] = 'Komprimierung (Code Layout):'; +$lang['de'][13] = 'Höchste (keine Lesbarkeit, niedrigste Größe)'; +$lang['de'][14] = 'Hoch (mittelmäßige Lesbarkeit, geringe Größe)'; +$lang['de'][15] = 'Standard (Kompromiss zwischen Lesbarkeit und Größe)'; +$lang['de'][16] = 'Niedrig (höhere Lesbarkeit)'; +$lang['de'][17] = 'Benutzerdefiniert (unten eingeben)'; +$lang['de'][18] = 'Benutzerdefinierte <a href="http://csstidy.sourceforge.net/templates.php">Vorlage</a>'; +$lang['de'][19] = 'Optionen'; +$lang['de'][20] = 'Selektoren sortieren (Vorsicht)'; +$lang['de'][21] = 'Eigenschaften sortieren'; +$lang['de'][22] = 'Selektoren umgruppieren'; +$lang['de'][23] = 'Shorthands optimieren'; +$lang['de'][24] = 'Farben komprimieren'; +$lang['de'][25] = 'Selektoren in Kleinbuchstaben'; +$lang['de'][26] = 'Groß-/Kleinschreibung für Eigenschaften'; +$lang['de'][27] = 'Kleinbuchstaben'; +$lang['de'][28] = 'Keine oder ungültige CSS Eingabe oder falsche URL!'; +$lang['de'][29] = 'Großbuchstaben'; +$lang['de'][30] = 'kleingeschriebene Elementnamen benötigt für XHTML'; +$lang['de'][31] = 'Unnötige Backslashes entfernen'; +$lang['de'][32] = '!important-Hack konvertieren'; +$lang['de'][33] = 'Als Datei ausgeben'; +$lang['de'][34] = 'Größere Komprimierung augrund von kleineren Neuezeile-Zeichen'; +$lang['de'][35] = 'CSS verarbeiten'; +$lang['de'][36] = 'Komprimierungsrate'; +$lang['de'][37] = 'Eingabe'; +$lang['de'][38] = 'Ausgabe'; +$lang['de'][39] = 'Sprache'; +$lang['de'][41] = 'Achtung: Dies könnte das Verhalten ihres CSS-Codes verändern!'; +$lang['de'][42] = 'Letztes ; entfernen'; +$lang['de'][43] = 'Ungültige Eigenschaften entfernen'; +$lang['de'][44] = 'Nur sichere Optimierungen'; +$lang['de'][45] = 'font-weight komprimieren'; +$lang['de'][46] = 'Kommentare beibehalten'; +$lang['de'][47] = 'Nichts ändern'; +$lang['de'][48] = 'Selektoren nur trennen (am Komma)'; +$lang['de'][49] = 'Selektoren mit gleichen Eigenschaften zusammenfassen (schnell)'; +$lang['de'][50] = 'Selektoren intelligent zusammenfassen (langsam!)'; +$lang['de'][51] = 'CSS erhalten'; +$lang['de'][52] = 'Kommentare, Hacks, etc. speichern. Viele Optimierungen sind dann aber nicht mehr möglich.'; +$lang['de'][53] = 'Keine'; +$lang['de'][54] = 'Nicht optimieren'; +$lang['de'][55] = 'Sichere Optimierungen'; +$lang['de'][56] = 'Alle Optimierungen'; +$lang['de'][57] = 'Zeitstempel hinzufügen'; +$lang['de'][58] = 'Copy to clipboard'; +$lang['de'][59] = 'Back to top'; +$lang['de'][60] = 'Your browser doesn\'t support copy to clipboard.'; +$lang['de'][61] = 'For bugs and suggestions feel free to'; +$lang['de'][62] = 'contact me'; +$lang['de'][63] = 'Output CSS code as complete HTML document'; +$lang['de'][64] = 'Code'; +$lang['de'][65] = 'CSS to style CSS output'; +$lang['de'][66] = 'You need to go to about:config in your URL bar, select \'signed.applets.codebase_principal_support\' in the filter field, and set its value to true in order to use this feature; however, be aware that doing so increases security risks.'; + +$lang['fr'][0] = 'CSS Formatteur et Optimiseur (basé sur CSSTidy '; +$lang['fr'][1] = 'CSS Formatteur et Optimiseur'; +$lang['fr'][2] = '(basé sur '; +$lang['fr'][3] = '(Version texte)'; +$lang['fr'][4] = 'Note Importante :'; +$lang['fr'][6] = 'Votre code doit être valide. Ce n’est <strong>pas un validateur</strong> qui signale les erreurs dans votre code CSS. Pour être sûr que votre code est correct, utilisez le validateur : <a href="https://jigsaw.w3.org/css-validator/">W3C Validator</a>.'; +$lang['fr'][7] = 'tous les commentaires sont enlevés'; +$lang['fr'][8] = 'Champ CSS :'; +$lang['fr'][9] = 'Code CSS :'; +$lang['fr'][10] = 'CSS en provenance d’une URL :<br />'; +$lang['fr'][11] = 'Mise en page du code :'; +$lang['fr'][12] = 'Compression (mise en page du code) :'; +$lang['fr'][13] = 'La plus élevée (aucune lisibilité, taille minimale)'; +$lang['fr'][14] = 'Élevée (lisibilité modérée, petite taille)'; +$lang['fr'][15] = 'Normale (équilibre entre lisibilité et taille)'; +$lang['fr'][16] = 'Faible (lisibilité élevée)'; +$lang['fr'][17] = 'Sur mesure (entrer ci-dessous)'; +$lang['fr'][18] = '<a href="http://csstidy.sourceforge.net/templates.php">Gabarit</a> sur mesure'; +$lang['fr'][19] = 'Options'; +$lang['fr'][20] = 'Trier les sélecteurs (attention)'; +$lang['fr'][21] = 'Trier les propriétés'; +$lang['fr'][22] = 'Regrouper les sélecteurs'; +$lang['fr'][23] = 'Propriétés raccourcies'; +$lang['fr'][24] = 'Compresser les couleurs'; +$lang['fr'][25] = 'Sélecteurs en minuscules'; +$lang['fr'][26] = 'Case pour les propriétés :'; +$lang['fr'][27] = 'Minuscule'; +$lang['fr'][28] = 'CSS non valide ou URL incorrecte !'; +$lang['fr'][29] = 'Majuscule'; +$lang['fr'][30] = 'les noms des éléments en minuscules (indispensables pour XHTML)'; +$lang['fr'][31] = 'enlever les antislashs inutiles'; +$lang['fr'][32] = 'convertir !important-hack'; +$lang['fr'][33] = 'Sauver en tant que fichier'; +$lang['fr'][34] = 'Meilleure compression grâce aux caractères de saut de ligne plus petits (copier & coller ne marche pas)'; +$lang['fr'][35] = 'Compresser la CSS'; +$lang['fr'][36] = 'Facteur de Compression'; +$lang['fr'][37] = 'Entrée'; +$lang['fr'][38] = 'Sortie'; +$lang['fr'][39] = 'Langue'; +$lang['fr'][41] = 'Attention : ceci peut changer le comportement de votre code CSS !'; +$lang['fr'][42] = 'Enlever le dernier ;'; +$lang['fr'][43] = 'Supprimer les propriétés non valide'; +$lang['fr'][44] = 'Seulement les optimisations sûres'; +$lang['fr'][45] = 'Compresser font-weight'; +$lang['fr'][46] = 'Sauvegarder les commentaires '; +$lang['fr'][47] = 'Ne rien changer'; +$lang['fr'][48] = 'Sépare les sélecteurs (sépare au niveau de ,)'; +$lang['fr'][49] = 'Fusionne les sélecteurs avec les mêmes propriétés (rapide)'; +$lang['fr'][50] = 'Fusionne les sélecteurs intelligemment (lent)'; +$lang['fr'][51] = 'Préserver la CSS'; +$lang['fr'][52] = 'Sauvegarder les commentaires, hacks, etc. La plupart des optimisations ne peuvent *pas* être appliquées si cela est activé.'; +$lang['fr'][53] = 'Aucun'; +$lang['fr'][54] = 'Ne pas optimiser'; +$lang['fr'][55] = 'Optimisations sûres'; +$lang['fr'][56] = 'Toutes les optimisations'; +$lang['fr'][57] = 'Ajouter un timestamp'; +$lang['fr'][58] = 'Copier dans le presse-papiers'; +$lang['fr'][59] = 'Retour en haut'; +$lang['fr'][60] = 'Votre navigateur ne suporte pas la copie vers le presse-papiers.'; +$lang['fr'][61] = 'Pour signaler des bugs ou pour des suggestions,'; +$lang['fr'][62] = 'contactez-moi'; +$lang['fr'][63] = 'Sauver le code CSS comme document complet HTML'; +$lang['fr'][64] = 'Code'; +$lang['fr'][65] = 'CSS pour colorier la sortie CSS'; +$lang['fr'][66] = 'Vous devez aller dans about:config dans votre barre d’adresse, selectionner \'signed.applets.codebase_principal_support\' dans le champ Filtre et attribuez-lui la valeur \'true\' pour utiliser cette fonctionnalité; toutefois, soyez conscient que cela augmente les risques de sécurité.'; + +$lang['zh'][0] = 'CSS整形與最佳化工具(使用 CSSTidy '; +$lang['zh'][1] = 'CSS整形與最佳化工具'; +$lang['zh'][2] = '(使用'; +$lang['zh'][3] = '(純文字)'; +$lang['zh'][4] = '重要事項:'; +$lang['zh'][6] = '你的原始碼必須是良構的(well-formed). 這個工具<strong>沒有內建驗證器(validator)</strong>. 驗證器能夠指出你CSS原始碼裡的錯誤. 請使用 <a href="https://jigsaw.w3.org/css-validator/">W3C 驗證器</a>, 確保你的原始碼合乎規範.'; +$lang['zh'][7] = '所有註解都移除了'; +$lang['zh'][8] = 'CSS 輸入:'; +$lang['zh'][9] = 'CSS 原始碼:'; +$lang['zh'][10] = 'CSS 檔案網址(URL):'; +$lang['zh'][11] = '原始碼規劃:'; +$lang['zh'][12] = '壓縮程度(原始碼規劃):'; +$lang['zh'][13] = '最高 (沒有辦法讀, 檔案最小)'; +$lang['zh'][14] = '高 (適度的可讀性, 檔案小)'; +$lang['zh'][15] = '標準 (兼顧可讀性與檔案大小)'; +$lang['zh'][16] = '低 (注重可讀性)'; +$lang['zh'][17] = '自訂 (在下方設定)'; +$lang['zh'][18] = '自訂<a href="http://csstidy.sourceforge.net/templates.php">樣板</a>'; +$lang['zh'][19] = '選項'; +$lang['zh'][20] = '整理選擇符(請謹慎使用)'; +$lang['zh'][21] = '整理屬性'; +$lang['zh'][22] = '重組選擇符'; +$lang['zh'][23] = '速記法(shorthand)最佳化'; +$lang['zh'][24] = '壓縮色彩語法'; +$lang['zh'][25] = '改用小寫選擇符'; +$lang['zh'][26] = '屬性的字形:'; +$lang['zh'][27] = '小寫'; +$lang['zh'][28] = '沒有輸入CSS, 語法不符合規定, 或是網址錯誤!'; +$lang['zh'][29] = '大寫'; +$lang['zh'][30] = 'XHTML必須使用小寫的元素名稱'; +$lang['zh'][31] = '移除不必要的反斜線'; +$lang['zh'][32] = '轉換 !important-hack'; +$lang['zh'][33] = '輸出成檔案形式'; +$lang['zh'][34] = '由於比較少換行字元, 會有更大的壓縮比率(複製&貼上沒有用)'; +$lang['zh'][35] = '執行'; +$lang['zh'][36] = '壓縮比率'; +$lang['zh'][37] = '輸入'; +$lang['zh'][38] = '輸出'; +$lang['zh'][39] = '語言'; +$lang['zh'][41] = '注意: 這或許會變更你CSS原始碼的行為!'; +$lang['zh'][42] = '除去最後一個分號'; +$lang['zh'][43] = '拋棄不符合規定的屬性'; +$lang['zh'][44] = '只安全地最佳化'; +$lang['zh'][45] = '壓縮 font-weight'; +$lang['zh'][46] = '保留註解'; +$lang['zh'][47] = '什麼都不要改'; +$lang['zh'][48] = '只分開原本用逗號分隔的選擇符'; +$lang['zh'][49] = '合併有相同屬性的選擇符(快速)'; +$lang['zh'][50] = '聰明地合併選擇符(慢速)'; +$lang['zh'][51] = '保護CSS'; +$lang['zh'][52] = '保留註解與 hack 等等. 如果啟用這個選項, 大多數的最佳化程序都不會執行.'; +$lang['zh'][53] = '不改變'; +$lang['zh'][54] = '不做最佳化'; +$lang['zh'][55] = '安全地最佳化'; +$lang['zh'][56] = '全部最佳化'; +$lang['zh'][57] = '加上時間戳記'; +$lang['zh'][58] = '复制到剪贴板'; +$lang['zh'][59] = '回到页面上方'; +$lang['zh'][60] = '你的浏览器不支持复制到剪贴板。'; +$lang['zh'][61] = '如果程序有错误或你有建议,欢迎'; +$lang['zh'][62] = '和我联系'; +$lang['zh'][63] = 'Output CSS code as complete HTML document'; +$lang['zh'][64] = '代码'; +$lang['zh'][65] = 'CSS to style CSS output'; +$lang['zh'][66] = 'You need to go to about:config in your URL bar, select \'signed.applets.codebase_principal_support\' in the filter field, and set its value to true in order to use this feature; however, be aware that doing so increases security risks.'; diff --git a/csstidy/wordpress-standard.tpl b/csstidy/wordpress-standard.tpl new file mode 100644 index 0000000..9499e83 --- /dev/null +++ b/csstidy/wordpress-standard.tpl @@ -0,0 +1,10 @@ +| { +|| { +| | |; +|}| + +| +} + +| || +| diff --git a/custom-css.php b/custom-css.php new file mode 100644 index 0000000..f186afb --- /dev/null +++ b/custom-css.php @@ -0,0 +1,73 @@ +<?php +/* + * Plugin Name: A/I - Sanitize Custom CSS + * Description: Sanitize Custom CSS by preventing url() references + * Version: 0.0.1 + * Author: Autistici/Inventati + * Author URI: https://autistici.org + */ + +// The following code is heavily inspired by the Jetpack plugin custom-css module. +function ai_sanitize_css( $css, $args = array() ) { + require_once(__DIR__ . '/csstidy/class.csstidy.php'); + + $args = wp_parse_args( + $args, + array( + 'force' => false, + ) + ); + + if ($args['force'] || !current_user_can('unfiltered_html')) { + $warnings = array(); + + safecss_class(); + $csstidy = new csstidy(); + $csstidy->optimise = new safecss( $csstidy ); + + $csstidy->set_cfg( 'remove_bslash', false ); + $csstidy->set_cfg( 'compress_colors', false ); + $csstidy->set_cfg( 'compress_font-weight', false ); + $csstidy->set_cfg( 'optimise_shorthands', 0 ); + $csstidy->set_cfg( 'remove_last_;', false ); + $csstidy->set_cfg( 'case_properties', false ); + $csstidy->set_cfg( 'discard_invalid_properties', true ); + $csstidy->set_cfg( 'css_level', 'CSS3.0' ); + $csstidy->set_cfg( 'preserve_css', true ); + $csstidy->set_cfg( 'template', __DIR__ . '/csstidy/wordpress-standard.tpl' ); + + // Test for some preg_replace stuff. + $prev = $css; + $css = preg_replace( '/\\\\([0-9a-fA-F]{4})/', '\\\\\\\\$1', $css ); + // prevent content: '\3434' from turning into '\\3434'. + $css = str_replace( array( '\'\\\\', '"\\\\' ), array( '\'\\', '"\\' ), $css ); + if ( $css !== $prev ) { + $warnings[] = 'preg_replace found stuff'; + } + + // Some people put weird stuff in their CSS, KSES tends to be greedy. + $css = str_replace( '<=', '<=', $css ); + + // Test for some kses stuff. + $prev = $css; + // Why KSES instead of strip_tags? Who knows? + $css = wp_kses_split( $css, array(), array() ); + $css = str_replace( '>', '>', $css ); // kses replaces lone '>' with > + // Why both KSES and strip_tags? Because we just added some '>'. + $css = strip_tags( $css ); // phpcs:ignore WordPress.WP.AlternativeFunctions.strip_tags_strip_tags -- scared to update this to wp_strip_all_tags since we're building a CSS file here. + + if ( $css !== $prev ) { + $warnings[] = 'kses found stuff'; + } + + $csstidy->parse( $css ); + $css = $csstidy->print->plain(); + } + return $css; +} + +add_filter('update_custom_css_data', function($args) { + $css = $args['css']; + $args['css'] = ai_sanitize_css($css); + return $args; +}, 10, 2); -- GitLab