1
1
<?php
2
2
/**
3
3
* 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) <[email protected] >
9
+ * @license MIT
10
+ * @web http://csscomb.com/
7
11
*/
8
-
12
+
9
13
error_reporting (E_ALL );
10
-
14
+
11
15
class csscomb{
12
16
13
17
var $ sort_order = Array (),
@@ -24,6 +28,8 @@ class csscomb{
24
28
'expressions ' => null ,
25
29
// если найдены data uri, то эта переменная станет массивом...
26
30
'datauri ' => null ,
31
+ // если найдены интерполированные переменные, то эта переменная станет массивом
32
+ 'interpolations ' => null ,
27
33
// если найдены CSS-хаки мешающие парсить, то эта переменная станет массивом...
28
34
'hacks ' => null ,
29
35
// если найдены комментарии содержащие { или } мешающие парсить,
@@ -125,18 +131,18 @@ class csscomb{
125
131
"-webkit-border-radius",
126
132
"-moz-border-radius",
127
133
"border-radius",
134
+ "-webkit-border-top-left-radius",
135
+ "-moz-border-radius-topleft",
136
+ "border-top-left-radius",
128
137
"-webkit-border-top-right-radius",
129
- "-moz-border-top-right- radius",
138
+ "-moz-border-radius-topright ",
130
139
"border-top-right-radius",
131
140
"-webkit-border-bottom-right-radius",
132
- "-moz-border-bottom-right- radius",
141
+ "-moz-border-radius-bottomright ",
133
142
"border-bottom-right-radius",
134
143
"-webkit-border-bottom-left-radius",
135
- "-moz-border-bottom-left- radius",
144
+ "-moz-border-radius-bottomleft ",
136
145
"border-bottom-left-radius",
137
- "-webkit-border-top-left-radius",
138
- "-moz-border-top-left-radius",
139
- "border-top-left-radius",
140
146
"-webkit-border-image",
141
147
"-moz-border-image",
142
148
"-o-border-image",
@@ -362,7 +368,7 @@ class csscomb{
362
368
"-ms-animation-direction",
363
369
"-o-animation-direction",
364
370
"animation-direction",
365
- "pointer-event ",
371
+ "pointer-events ",
366
372
"unicode-bidi",
367
373
"direction",
368
374
"-webkit-columns",
@@ -597,7 +603,7 @@ class csscomb{
597
603
"-webkit-hyphens",
598
604
"-moz-hyphens",
599
605
"hyphens",
600
- "pointer-event "
606
+ "pointer-events "
601
607
],
602
608
[
603
609
"opacity",
@@ -629,18 +635,18 @@ class csscomb{
629
635
"-webkit-border-radius",
630
636
"-moz-border-radius",
631
637
"border-radius",
638
+ "-webkit-border-top-left-radius",
639
+ "-moz-border-radius-topleft",
640
+ "border-top-left-radius",
632
641
"-webkit-border-top-right-radius",
633
- "-moz-border-top-right- radius",
642
+ "-moz-border-radius-topright ",
634
643
"border-top-right-radius",
635
644
"-webkit-border-bottom-right-radius",
636
- "-moz-border-bottom-right- radius",
645
+ "-moz-border-radius-bottomright ",
637
646
"border-bottom-right-radius",
638
647
"-webkit-border-bottom-left-radius",
639
- "-moz-border-bottom-left- radius",
648
+ "-moz-border-radius-bottomleft ",
640
649
"border-bottom-left-radius",
641
- "-webkit-border-top-left-radius",
642
- "-moz-border-top-left-radius",
643
- "border-top-left-radius",
644
650
"-webkit-border-image",
645
651
"-moz-border-image",
646
652
"-o-border-image",
@@ -721,11 +727,25 @@ class csscomb{
721
727
722
728
/**
723
729
* @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
727
733
*
728
734
* @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
+ *
729
749
*/
730
750
function csscomb ($ css = '' , $ debug = false , $ custom_sort_order = null ) {
731
751
$ this ->output = $ debug ? true : false ;
@@ -877,18 +897,27 @@ function preprocess() {
877
897
endwhile ;
878
898
}
879
899
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. Закрываем сложности парсинга {}
881
910
$ this ->code ['edited ' ] = str_replace ('{} ' , '{ } ' , $ this ->code ['edited ' ]);
882
911
883
- // 5 . Закрываем сложности с отсутствующей последней ; перед }
912
+ // 6 . Закрываем сложности с отсутствующей последней ; перед }
884
913
$ this ->code ['edited ' ] = preg_replace ('@(.*?[^\s;\{\}\/\*])(\s*?})@ ' , '$1;$2 ' , $ this ->code ['edited ' ]);
885
914
// Убираем ; у последнего инлайнового комментария
886
915
// Инлайновый комментарий может идти только после фигурной скобки или ;
887
916
$ this ->code ['edited ' ] = preg_replace ('@([;\{\}]+\s*?//.*?);(\s*?})@ ' , '$1$2 ' , $ this ->code ['edited ' ]);
888
917
// Убираем ; у интерполированных переменных
889
- $ this ->code ['edited ' ] = preg_replace ('@( #\{\$.*?)[;](\s*?\})@ ' , '$1$2 ' , $ this ->code ['edited ' ]);
918
+ $ this ->code ['edited ' ] = preg_replace ('/(( #\{\$|\@\{) .*?)[;](\s*?\})/ ' , '$1$3 ' , $ this ->code ['edited ' ]);
890
919
891
- // 6 . Комментарии
920
+ // 7 . Комментарии
892
921
if (preg_match_all ('@
893
922
(
894
923
\s*
@@ -899,7 +928,7 @@ function preprocess() {
899
928
)
900
929
@ismx ' , $ this ->code ['edited ' ], $ test )) {
901
930
902
- // 6 .1. Закомментировано одно или несколько свойств: повторяющийся паттерн *:*; \s*?
931
+ // 7 .1. Закомментировано одно или несколько свойств: повторяющийся паттерн *:*; \s*?
903
932
if (preg_match_all ('@
904
933
(\s*)
905
934
/\*
@@ -948,7 +977,7 @@ function preprocess() {
948
977
}
949
978
}
950
979
951
- // 6 .2. Обрывки закомментированных деклараций: присутствует { или }
980
+ // 7 .2. Обрывки закомментированных деклараций: присутствует { или }
952
981
if (preg_match_all ('@
953
982
\s*?
954
983
/\*
@@ -983,7 +1012,7 @@ function preprocess() {
983
1012
}
984
1013
}
985
1014
986
- // 7 . Entities
1015
+ // 8 . Entities
987
1016
if (preg_match_all ('@
988
1017
\&
989
1018
\#?
@@ -1092,28 +1121,37 @@ function parse_root($css = '') {
1092
1121
*
1093
1122
*/
1094
1123
function parse_child ($ value = '' ) {
1124
+ $ block_imports = array ();
1095
1125
// 1. Ищем «детей» (вложенные селекторы)
1096
1126
preg_match_all ('@
1097
- [^\};]*?[\s]*?\{((([^\{\}]+)|(?R))*)\}
1127
+ [^};]*?
1128
+ {
1129
+ (
1130
+ (
1131
+ ([^\{\}]+)|(?R)
1132
+ )*
1133
+ )
1134
+ }
1098
1135
@ismx ' , $ value , $ nested );
1099
1136
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 ]);
1104
1148
}
1105
1149
}
1106
1150
1107
1151
// Сохраняем всех «детей» в строку для последующей замены
1108
1152
// TODO: убрать, если без этого можно обойтись
1109
1153
$ nested_string = implode ('' , $ nested [0 ]);
1110
1154
1111
- // Удаляем «детей» из общей строки
1112
- // TODO: возможно, вынести отдельной функцией, т.к. часто повторяется
1113
- foreach ($ nested [0 ] as &$ nest ) {
1114
- $ value = str_replace ($ nest , '' , $ value );
1115
- }
1116
-
1117
1155
// Рекурсия, ahoj!
1118
1156
// Сортируем содержимое «детей»
1119
1157
foreach ($ nested [1 ] as &$ child ) {
@@ -1140,20 +1178,23 @@ function parse_child($value = '') {
1140
1178
1141
1179
// Включения, следующие сразу за {
1142
1180
preg_match_all ('@
1143
- ^\s*\@[^;]+?[;]
1181
+ ( ^\s*\@[^;]+?[;])|(^\s*\.[^;:]+?[;])
1144
1182
@isx ' , $ value , $ first_imports );
1145
1183
foreach ($ first_imports [0 ] as &$ first_import ) {
1146
1184
$ value = str_replace ($ first_import , '' , $ value );
1147
1185
}
1148
1186
1149
1187
// Все остальные
1150
1188
preg_match_all ('@
1151
- [;\{\}]+( \s*\@ [^;]+?[;])
1189
+ (?<=[;}])(\s*\@[^;]+?[;])|(?<=[;}])( \s*\. [^;: ]+?[;])
1152
1190
@ismx ' , $ value , $ imports );
1153
1191
// Удаляем их из общей строки
1154
1192
foreach ($ imports [1 ] as &$ import ) {
1155
1193
$ value = str_replace ($ import , '' , $ value );
1156
1194
}
1195
+ foreach ($ imports [2 ] as &$ import ) {
1196
+ $ value = str_replace ($ import , '' , $ value );
1197
+ }
1157
1198
1158
1199
// 4. Выносим простые свойства в массив $properties
1159
1200
preg_match_all ('@
@@ -1173,7 +1214,7 @@ function parse_child($value = '') {
1173
1214
1174
1215
// 6. Склеиваем всё обратно в следующем порядке:
1175
1216
// переменные, включения, простые свойства, вложенные {}
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 ;
1177
1218
return $ value ;
1178
1219
}
1179
1220
@@ -1443,7 +1484,13 @@ function postprocess() {
1443
1484
}
1444
1485
}
1445
1486
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__'
1447
1494
while (strpos ($ this ->code ['resorted ' ], 'commented__ ' ) !== FALSE ) {
1448
1495
$ this ->code ['resorted ' ] = preg_replace (
1449
1496
'#
@@ -1458,7 +1505,7 @@ function postprocess() {
1458
1505
);
1459
1506
}
1460
1507
1461
- // 5 . Удаляем искусственно созданные 'brace__'
1508
+ // 6 . Удаляем искусственно созданные 'brace__'
1462
1509
if (is_array ($ this ->code ['braces ' ])) { // если были обнаружены и вырезаны хаки
1463
1510
foreach ($ this ->code ['braces ' ] as $ key => $ val ) {
1464
1511
if (strpos ($ this ->code ['resorted ' ], 'brace__ ' .$ key .'{ ' ) !== FALSE ) {
0 commit comments