Subversion-Projekte lars-tiefland.laravel_shop

Revision

Details | Letzte Änderung | Log anzeigen | RSS feed

Revision Autor Zeilennr. Zeile
148 lars 1
<?php
2
 
3
namespace TijsVerkoyen\CssToInlineStyles\Css\Rule;
4
 
5
use Symfony\Component\CssSelector\Node\Specificity;
6
use \TijsVerkoyen\CssToInlineStyles\Css\Property\Processor as PropertyProcessor;
7
 
8
class Processor
9
{
10
    /**
11
     * Splits a string into separate rules
12
     *
13
     * @param string $rulesString
14
     *
15
     * @return string[]
16
     */
17
    public function splitIntoSeparateRules($rulesString)
18
    {
19
        $rulesString = $this->cleanup($rulesString);
20
 
21
        return (array) explode('}', $rulesString);
22
    }
23
 
24
    /**
25
     * @param string $string
26
     *
27
     * @return string
28
     */
29
    private function cleanup($string)
30
    {
31
        $string = str_replace(array("\r", "\n"), '', $string);
32
        $string = str_replace(array("\t"), ' ', $string);
33
        $string = str_replace('"', '\'', $string);
34
        $string = preg_replace('|/\*.*?\*/|', '', $string);
35
        $string = preg_replace('/\s\s+/', ' ', $string);
36
 
37
        $string = trim($string);
38
        $string = rtrim($string, '}');
39
 
40
        return $string;
41
    }
42
 
43
    /**
44
     * Converts a rule-string into an object
45
     *
46
     * @param string $rule
47
     * @param int    $originalOrder
48
     *
49
     * @return Rule[]
50
     */
51
    public function convertToObjects($rule, $originalOrder)
52
    {
53
        $rule = $this->cleanup($rule);
54
 
55
        $chunks = explode('{', $rule);
56
        if (!isset($chunks[1])) {
57
            return array();
58
        }
59
        $propertiesProcessor = new PropertyProcessor();
60
        $rules = array();
61
        $selectors = (array) explode(',', trim($chunks[0]));
62
        $properties = $propertiesProcessor->splitIntoSeparateProperties($chunks[1]);
63
 
64
        foreach ($selectors as $selector) {
65
            $selector = trim($selector);
66
            $specificity = $this->calculateSpecificityBasedOnASelector($selector);
67
 
68
            $rules[] = new Rule(
69
                $selector,
70
                $propertiesProcessor->convertArrayToObjects($properties, $specificity),
71
                $specificity,
72
                $originalOrder
73
            );
74
        }
75
 
76
        return $rules;
77
    }
78
 
79
    /**
80
     * Calculates the specificity based on a CSS Selector string,
81
     * Based on the patterns from premailer/css_parser by Alex Dunae
82
     *
83
     * @see https://github.com/premailer/css_parser/blob/master/lib/css_parser/regexps.rb
84
     *
85
     * @param string $selector
86
     *
87
     * @return Specificity
88
     */
89
    public function calculateSpecificityBasedOnASelector($selector)
90
    {
91
        $idSelectorsPattern = "  \#";
92
        $classAttributesPseudoClassesSelectorsPattern = "  (\.[\w]+)                     # classes
93
                        |
94
                        \[(\w+)                       # attributes
95
                        |
96
                        (\:(                          # pseudo classes
97
                          link|visited|active
98
                          |hover|focus
99
                          |lang
100
                          |target
101
                          |enabled|disabled|checked|indeterminate
102
                          |root
103
                          |nth-child|nth-last-child|nth-of-type|nth-last-of-type
104
                          |first-child|last-child|first-of-type|last-of-type
105
                          |only-child|only-of-type
106
                          |empty|contains
107
                        ))";
108
 
109
        $typePseudoElementsSelectorPattern = "  ((^|[\s\+\>\~]+)[\w]+       # elements
110
                        |
111
                        \:{1,2}(                    # pseudo-elements
112
                          after|before
113
                          |first-letter|first-line
114
                          |selection
115
                        )
116
                      )";
117
 
118
        return new Specificity(
119
            preg_match_all("/{$idSelectorsPattern}/ix", $selector, $matches),
120
            preg_match_all("/{$classAttributesPseudoClassesSelectorsPattern}/ix", $selector, $matches),
121
            preg_match_all("/{$typePseudoElementsSelectorPattern}/ix", $selector, $matches)
122
        );
123
    }
124
 
125
    /**
126
     * @param string[] $rules
127
     * @param Rule[]   $objects
128
     *
129
     * @return Rule[]
130
     */
131
    public function convertArrayToObjects(array $rules, array $objects = array())
132
    {
133
        $order = 1;
134
        foreach ($rules as $rule) {
135
            $objects = array_merge($objects, $this->convertToObjects($rule, $order));
136
            $order++;
137
        }
138
 
139
        return $objects;
140
    }
141
 
142
    /**
143
     * Sorts an array on the specificity element in an ascending way
144
     * Lower specificity will be sorted to the beginning of the array
145
     *
146
     * @param Rule $e1 The first element.
147
     * @param Rule $e2 The second element.
148
     *
149
     * @return int
150
     */
151
    public static function sortOnSpecificity(Rule $e1, Rule $e2)
152
    {
153
        $e1Specificity = $e1->getSpecificity();
154
        $value = $e1Specificity->compareTo($e2->getSpecificity());
155
 
156
        // if the specificity is the same, use the order in which the element appeared
157
        if ($value === 0) {
158
            $value = $e1->getOrder() - $e2->getOrder();
159
        }
160
 
161
        return $value;
162
    }
163
}