11<?php
22/**
33 * CSScomb
4- * @version: 2.11 (build 3ded73c-1208080145)
5- * @author: Vyacheslav Oliyanchuk (miripiruni)
6- * @web: http://csscomb.com/
4+ *
5+ * Tool for sorting CSS properties in specific order
6+ *
7+ * @version 2.12 (build e784736-1301040046)
8+ * @author Vyacheslav Oliyanchuk (miripiruni) <mail@csscomb.com>
9+ * @license MIT
10+ * @web http://csscomb.com/
711 */
8-
12+
913error_reporting (E_ALL );
10-
14+
1115class csscomb{
1216
1317 var $ sort_order = Array (),
@@ -24,6 +28,8 @@ class csscomb{
2428 'expressions ' => null ,
2529 // если найдены data uri, то эта переменная станет массивом...
2630 'datauri ' => null ,
31+ // если найдены интерполированные переменные, то эта переменная станет массивом
32+ 'interpolations ' => null ,
2733 // если найдены CSS-хаки мешающие парсить, то эта переменная станет массивом...
2834 'hacks ' => null ,
2935 // если найдены комментарии содержащие { или } мешающие парсить,
@@ -125,18 +131,18 @@ class csscomb{
125131 "-webkit-border-radius",
126132 "-moz-border-radius",
127133 "border-radius",
134+ "-webkit-border-top-left-radius",
135+ "-moz-border-radius-topleft",
136+ "border-top-left-radius",
128137 "-webkit-border-top-right-radius",
129- "-moz-border-top-right- radius",
138+ "-moz-border-radius-topright ",
130139 "border-top-right-radius",
131140 "-webkit-border-bottom-right-radius",
132- "-moz-border-bottom-right- radius",
141+ "-moz-border-radius-bottomright ",
133142 "border-bottom-right-radius",
134143 "-webkit-border-bottom-left-radius",
135- "-moz-border-bottom-left- radius",
144+ "-moz-border-radius-bottomleft ",
136145 "border-bottom-left-radius",
137- "-webkit-border-top-left-radius",
138- "-moz-border-top-left-radius",
139- "border-top-left-radius",
140146 "-webkit-border-image",
141147 "-moz-border-image",
142148 "-o-border-image",
@@ -362,7 +368,7 @@ class csscomb{
362368 "-ms-animation-direction",
363369 "-o-animation-direction",
364370 "animation-direction",
365- "pointer-event ",
371+ "pointer-events ",
366372 "unicode-bidi",
367373 "direction",
368374 "-webkit-columns",
@@ -597,7 +603,7 @@ class csscomb{
597603 "-webkit-hyphens",
598604 "-moz-hyphens",
599605 "hyphens",
600- "pointer-event "
606+ "pointer-events "
601607 ],
602608 [
603609 "opacity",
@@ -629,18 +635,18 @@ class csscomb{
629635 "-webkit-border-radius",
630636 "-moz-border-radius",
631637 "border-radius",
638+ "-webkit-border-top-left-radius",
639+ "-moz-border-radius-topleft",
640+ "border-top-left-radius",
632641 "-webkit-border-top-right-radius",
633- "-moz-border-top-right- radius",
642+ "-moz-border-radius-topright ",
634643 "border-top-right-radius",
635644 "-webkit-border-bottom-right-radius",
636- "-moz-border-bottom-right- radius",
645+ "-moz-border-radius-bottomright ",
637646 "border-bottom-right-radius",
638647 "-webkit-border-bottom-left-radius",
639- "-moz-border-bottom-left- radius",
648+ "-moz-border-radius-bottomleft ",
640649 "border-bottom-left-radius",
641- "-webkit-border-top-left-radius",
642- "-moz-border-top-left-radius",
643- "border-top-left-radius",
644650 "-webkit-border-image",
645651 "-moz-border-image",
646652 "-o-border-image",
@@ -721,11 +727,25 @@ class csscomb{
721727
722728 /**
723729 * @param string css
724- * @param boolean debug
725- * @param json custom_sort_order JSON expected
726- * @return string
730+ * @param boolean debug, OPTIONAL
731+ * @param json custom_sort_order JSON expected, OPTIONAL
732+ * @return string|false
727733 *
728734 * @TODO: https://github.com/miripiruni/CSScomb/issues/21
735+ *
736+ * Example:
737+ *
738+ * <code>
739+ * require_once 'PATH_TO_CSScomb/csscomb.php';
740+ *
741+ * $c = new csscomb();
742+ * $result_code = $c->csscomb(
743+ * 'div {margin-top:0; color: red; display: inline;}',
744+ * false,
745+ * $MY_JSON_SORT_ORDER
746+ * );
747+ * </code>
748+ *
729749 */
730750 function csscomb ($ css = '' , $ debug = false , $ custom_sort_order = null ) {
731751 $ this ->output = $ debug ? true : false ;
@@ -877,18 +897,27 @@ function preprocess() {
877897 endwhile ;
878898 }
879899
880- // 4. Закрываем сложности парсинга {}
900+ // 4. Interpolated variables
901+ preg_match_all ('@(\#|\@){.*?}@ismx ' , $ this ->code ['edited ' ], $ this ->code ['interpolations ' ]);
902+ foreach ($ this ->code ['interpolations ' ][0 ] as $ key => $ value ) {
903+ $ pos = strpos ($ this ->code ['edited ' ], $ value );
904+ if ($ pos !== false ) {
905+ $ this ->code ['edited ' ] = substr_replace ($ this ->code ['edited ' ],"interpolation " .$ key .'__ ' ,$ pos ,strlen ($ value ));
906+ }
907+ }
908+
909+ // 5. Закрываем сложности парсинга {}
881910 $ this ->code ['edited ' ] = str_replace ('{} ' , '{ } ' , $ this ->code ['edited ' ]);
882911
883- // 5 . Закрываем сложности с отсутствующей последней ; перед }
912+ // 6 . Закрываем сложности с отсутствующей последней ; перед }
884913 $ this ->code ['edited ' ] = preg_replace ('@(.*?[^\s;\{\}\/\*])(\s*?})@ ' , '$1;$2 ' , $ this ->code ['edited ' ]);
885914 // Убираем ; у последнего инлайнового комментария
886915 // Инлайновый комментарий может идти только после фигурной скобки или ;
887916 $ this ->code ['edited ' ] = preg_replace ('@([;\{\}]+\s*?//.*?);(\s*?})@ ' , '$1$2 ' , $ this ->code ['edited ' ]);
888917 // Убираем ; у интерполированных переменных
889- $ this ->code ['edited ' ] = preg_replace ('@( #\{\$.*?)[;](\s*?\})@ ' , '$1$2 ' , $ this ->code ['edited ' ]);
918+ $ this ->code ['edited ' ] = preg_replace ('/(( #\{\$|\@\{) .*?)[;](\s*?\})/ ' , '$1$3 ' , $ this ->code ['edited ' ]);
890919
891- // 6 . Комментарии
920+ // 7 . Комментарии
892921 if (preg_match_all ('@
893922 (
894923 \s*
@@ -899,7 +928,7 @@ function preprocess() {
899928 )
900929 @ismx ' , $ this ->code ['edited ' ], $ test )) {
901930
902- // 6 .1. Закомментировано одно или несколько свойств: повторяющийся паттерн *:*; \s*?
931+ // 7 .1. Закомментировано одно или несколько свойств: повторяющийся паттерн *:*; \s*?
903932 if (preg_match_all ('@
904933 (\s*)
905934 /\*
@@ -948,7 +977,7 @@ function preprocess() {
948977 }
949978 }
950979
951- // 6 .2. Обрывки закомментированных деклараций: присутствует { или }
980+ // 7 .2. Обрывки закомментированных деклараций: присутствует { или }
952981 if (preg_match_all ('@
953982 \s*?
954983 /\*
@@ -983,7 +1012,7 @@ function preprocess() {
9831012 }
9841013 }
9851014
986- // 7 . Entities
1015+ // 8 . Entities
9871016 if (preg_match_all ('@
9881017 \&
9891018 \#?
@@ -1092,28 +1121,37 @@ function parse_root($css = '') {
10921121 *
10931122 */
10941123 function parse_child ($ value = '' ) {
1124+ $ block_imports = array ();
10951125 // 1. Ищем «детей» (вложенные селекторы)
10961126 preg_match_all ('@
1097- [^\};]*?[\s]*?\{((([^\{\}]+)|(?R))*)\}
1127+ [^};]*?
1128+ {
1129+ (
1130+ (
1131+ ([^\{\}]+)|(?R)
1132+ )*
1133+ )
1134+ }
10981135 @ismx ' , $ value , $ nested );
10991136
1100- // Убираем из выборки интерполированные переменные
1101- foreach ($ nested [0 ] as $ nested_key => $ nested_value ) {
1102- if (strpos ($ nested_value , '#{$ ' )) {
1103- unset($ nested [0 ][$ nested_key ]);
1137+ // TODO: возможно, вынести отдельной функцией, т.к. часто повторяется
1138+ foreach ($ nested [0 ] as $ key => &$ nest ) {
1139+ $ value = str_replace ($ nest , '' , $ value );
1140+ if (strpos (trim ($ nest ), '@include ' ) === 0 ) {
1141+ $ value = str_replace ($ nest , '' , $ value );
1142+ $ old_nest = $ nested [1 ][$ key ];
1143+ $ new_nest = $ this ->parse_child ($ nested [1 ][$ key ]);
1144+ $ nest = str_replace ($ old_nest , $ new_nest , $ nest );
1145+ $ block_imports [] = $ nest ;
1146+ unset($ nested [0 ][$ key ]);
1147+ unset($ nested [1 ][$ key ]);
11041148 }
11051149 }
11061150
11071151 // Сохраняем всех «детей» в строку для последующей замены
11081152 // TODO: убрать, если без этого можно обойтись
11091153 $ nested_string = implode ('' , $ nested [0 ]);
11101154
1111- // Удаляем «детей» из общей строки
1112- // TODO: возможно, вынести отдельной функцией, т.к. часто повторяется
1113- foreach ($ nested [0 ] as &$ nest ) {
1114- $ value = str_replace ($ nest , '' , $ value );
1115- }
1116-
11171155 // Рекурсия, ahoj!
11181156 // Сортируем содержимое «детей»
11191157 foreach ($ nested [1 ] as &$ child ) {
@@ -1140,20 +1178,23 @@ function parse_child($value = '') {
11401178
11411179 // Включения, следующие сразу за {
11421180 preg_match_all ('@
1143- ^\s*\@[^;]+?[;]
1181+ ( ^\s*\@[^;]+?[;])|(^\s*\.[^;:]+?[;])
11441182 @isx ' , $ value , $ first_imports );
11451183 foreach ($ first_imports [0 ] as &$ first_import ) {
11461184 $ value = str_replace ($ first_import , '' , $ value );
11471185 }
11481186
11491187 // Все остальные
11501188 preg_match_all ('@
1151- [;\{\}]+( \s*\@ [^;]+?[;])
1189+ (?<=[;}])(\s*\@[^;]+?[;])|(?<=[;}])( \s*\. [^;: ]+?[;])
11521190 @ismx ' , $ value , $ imports );
11531191 // Удаляем их из общей строки
11541192 foreach ($ imports [1 ] as &$ import ) {
11551193 $ value = str_replace ($ import , '' , $ value );
11561194 }
1195+ foreach ($ imports [2 ] as &$ import ) {
1196+ $ value = str_replace ($ import , '' , $ value );
1197+ }
11571198
11581199 // 4. Выносим простые свойства в массив $properties
11591200 preg_match_all ('@
@@ -1173,7 +1214,7 @@ function parse_child($value = '') {
11731214
11741215 // 6. Склеиваем всё обратно в следующем порядке:
11751216 // переменные, включения, простые свойства, вложенные {}
1176- $ value = implode ('' , $ vars [0 ]).implode ('' , $ first_imports [0 ]).implode ('' , $ imports [1 ]).implode ('' , $ props ).$ nested_string .$ value ;
1217+ $ value = implode ('' , $ vars [0 ]).implode ('' , $ first_imports [0 ]).implode ('' , $ imports [1 ]).implode ('' , $ imports [ 2 ]). implode ( '' , $ block_imports ). implode ( '' , $ props ).$ nested_string .$ value ;
11771218 return $ value ;
11781219 }
11791220
@@ -1443,7 +1484,13 @@ function postprocess() {
14431484 }
14441485 }
14451486
1446- // 4. Удаляем искусственно созданные 'commented__'
1487+ // 4. Interpolated variables
1488+ preg_match_all ('#interpolation(\d)__#ismx ' , $ this ->code ['resorted ' ], $ new_vars );
1489+ foreach ($ new_vars [1 ] as $ key => $ value ) {
1490+ $ this ->code ['resorted ' ] = str_replace ($ new_vars [0 ][$ key ], $ this ->code ['interpolations ' ][0 ][$ key ], $ this ->code ['resorted ' ]);
1491+ }
1492+
1493+ // 5. Удаляем искусственно созданные 'commented__'
14471494 while (strpos ($ this ->code ['resorted ' ], 'commented__ ' ) !== FALSE ) {
14481495 $ this ->code ['resorted ' ] = preg_replace (
14491496 '#
@@ -1458,7 +1505,7 @@ function postprocess() {
14581505 );
14591506 }
14601507
1461- // 5 . Удаляем искусственно созданные 'brace__'
1508+ // 6 . Удаляем искусственно созданные 'brace__'
14621509 if (is_array ($ this ->code ['braces ' ])) { // если были обнаружены и вырезаны хаки
14631510 foreach ($ this ->code ['braces ' ] as $ key => $ val ) {
14641511 if (strpos ($ this ->code ['resorted ' ], 'brace__ ' .$ key .'{ ' ) !== FALSE ) {
0 commit comments