Subversion Repositories cheapmusic

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
115 - 1
<?php
2
 
3
class CSSParser {
4
  protected static $cssCounter = 0;
5
  protected static $propCounter = 0;
6
  protected $cssData;
7
 
8
  function __construct() {
9
    $this->cssData = array();
10
  }
11
 
12
  public function ParseCSS($css) {
13
    $index = ++self::$cssCounter;
14
    $this->cssData[$index] = array('all'=>array(),'screen'=>array(),'print'=>array());
15
    return $this->ParseCode($index, $css);
16
  }
17
 
18
  public function ParseCSSAppend($index, $css) {
19
    if(isset($this->cssData[$index])) {
20
      return $this->ParseCode($index, $css);
21
    } else {
22
      return $this->ParseCSS($css);
23
    }
24
  }
25
 
26
  public function ParseCSSMediaAppend($index, $css, $media) {
27
    $css = '@'.$media.' {'.PHP_EOL.$css.PHP_EOL.'}'.PHP_EOL;
28
    if(isset($this->cssData[$index])) {
29
      return $this->ParseCode($index, $css);
30
    }
31
    $index = ++self::$cssCounter;
32
    $this->cssData[$index] = array('all'=>array(),'screen'=>array(),'print'=>array());
33
    return $this->ParseCode($index, $css);
34
  }
35
 
36
  protected function ParseCode($index, $css) {
37
    $currentMedia = 'all';
38
    $mediaList = array();
39
    $section = false;
40
    $css = trim($css);
41
    if(strlen($css) == 0) {
42
      return $index;
43
    }
44
    $css = preg_replace('/\/\*.*\*\//Us', '', $css);
45
    while(preg_match('/^\s*(\@(media|import|local)([^\{\}]+)(\{)|([^\{\}]+)(\{)|([^\{\}]*)(\}))/Usi', $css, $match)) {
46
      if(isset($match[8]) && ($match[8] == '}')) {
47
        if($section !== false) {
48
          $code = trim($match[7]);
49
          $idx = 0;
50
          $inQuote = false;
51
          $property = false;
52
          $codeLen = strlen($code);
53
          $parenthesis = array();
54
          while($idx < $codeLen && isset($code{$idx})) {
55
            $c = $code{$idx};
56
            $idx++;
57
            if($inQuote !== false) {
58
              if($inQuote === $c) {
59
                $inQuote = false;
60
              }
61
            } elseif(($inQuote === false) && ($c == '(')) {
62
              array_push($parenthesis, '(');
63
            } elseif(($inQuote === false) && ($c == ')')) {
64
              array_pop($parenthesis);
65
            } elseif(($c == '\'') || ($c == '"')) {
66
              $inQuote = $c;
67
            } elseif(($property === false) && ($c == ':')) {
68
              $property = trim(substr($code, 0, $idx - 1));
69
              if(preg_match('/^(.*)\[([0-9]*)\]$/Us', $property, $propMatch)) {
70
                $property = $propMatch[1].'['.static::$propCounter.']';
71
                static::$propCounter += 1;
72
              }
73
              $code = substr($code, $idx);
74
              $idx = 0;
75
            } elseif((count($parenthesis) == 0) && ($c == ';')) {
76
              $value = trim(substr($code, 0, $idx - 1));
77
              $code = substr($code, $idx);
78
              $idx = 0;
79
              $this->AddProperty($index, $currentMedia, $section, $property, $value);
80
              $property = false;
81
            }
82
          }
83
          if(($idx > 0) && ($property !== false)) {
84
            $value = trim($code);
85
            $this->AddProperty($index, $currentMedia, $section, $property, $value);
86
          }
87
          $section = false;
88
        } elseif(count($mediaList) > 0) {
89
          array_pop($mediaList);
90
          if(count($mediaList) > 0) {
91
            $currentMedia = end($mediaList);
92
          } else {
93
            $currentMedia = 'all';
94
          }
95
        } else {
96
          // Superfluous }
97
        }
98
      } elseif(isset($match[6]) && ($match[6] == '{')) {
99
        // Section
100
        $section = trim($match[5]);
101
        if(!isset($this->cssData[$index][$currentMedia][$section])) {
102
          $this->cssData[$index][$currentMedia][$section] = array();
103
        }
104
      } elseif(isset($match[4]) && ($match[4] == '{')) {
105
        if($match[2] == 'media') {
106
          // New media
107
          $media = trim($match[3]);
108
          $mediaList[] = $media;
109
          $currentMedia = $media;
110
          if(!isset($this->cssData[$index][$currentMedia])) {
111
            $this->cssData[$index][$currentMedia] = array();
112
          }
113
        } elseif($match[2] == 'import') {
114
          // Can't support import (yet!)
115
        } elseif($match[2] == 'local') {
116
          // Can't support local import (yet!)
117
        }
118
      } else {
119
        // Shouldn't get here
120
      }
121
      $stripCount = strlen($match[0]);
122
      $css = trim(substr($css, $stripCount));
123
    }
124
    $css = trim($css);
125
    if(strlen($css) > 0) {
126
      echo "Potential error in stylesheet\n".$css;
127
    }
128
    return $index;
129
  }
130
 
131
  public function AddProperty($index, $media, $section, $property, $value) {
132
    if(!isset($this->cssData[$index])) {
133
      $this->cssData[$index] = array('all'=>array(),'screen'=>array(),'print'=>array());
134
    }
135
    $media = trim($media);
136
    if($media == '') {
137
      $media = 'all';
138
    }
139
    $section = trim($section);
140
    $property = trim($property);
141
    if(strlen($property) > 0) {
142
      $value = trim($value);
143
      if($media == 'all') {
144
        $this->cssData[$index][$media][$section][$property] = $value;
145
        $keys = array_keys($this->cssData[$index]);
146
        foreach($keys as $key) {
147
          if(!isset($this->cssData[$index][$key][$section])) {
148
            $this->cssData[$index][$key][$section] = array();
149
          }
150
          $this->cssData[$index][$key][$section][$property] = $value;
151
        }
152
      } else {
153
        if(!isset($this->cssData[$index][$media])) {
154
          $this->cssData[$index][$media] = $this->cssData[$index]['all'];
155
        }
156
        if(!isset($this->cssData[$index][$media][$section])) {
157
          $this->cssData[$index][$media][$section] = array();
158
        }
159
        $this->cssData[$index][$media][$section][$property] = $value;
160
      }
161
    }
162
  }
163
 
164
  public function GetMediaList($index) {
165
    if(isset($this->cssData[$index])) {
166
      return array_keys($this->cssData[$index]);
167
    }
168
    return array();
169
  }
170
 
171
  public function ExportKeyValues($index, $media, $keys) {
172
    $result = array();
173
    if(is_string($keys)) {
174
      $keys = array($keys);
175
    }
176
    if(!is_array($keys)) {
177
      return $result;
178
    }
179
    if(isset($this->cssData[$index]) && isset($this->cssData[$index][$media])) {
180
      foreach($this->cssData[$index][$media] as $section => $sectionValues) {
181
        foreach($sectionValues as $property => $value) {
182
          if(in_array($property, $keys)) {
183
            $result[] = $value;
184
          }
185
        }
186
      }
187
    }
188
    return $result;
189
  }
190
 
191
  public function ExportMedia($index, $media, $block = false) {
192
    $result = '';
193
    if(isset($this->cssData[$index]) && isset($this->cssData[$index][$media])) {
194
      foreach($this->cssData[$index][$media] as $section => $sectionValues) {
195
        $result .= "$section {\n";
196
        foreach($sectionValues as $property => $value) {
197
          $property = preg_replace('/(\[[0-9]*\])$/Usi', '', $property);
198
          if(is_array($block) && isset($block[$property])) {
199
            if(preg_match('/^'.static::ConvertWildcards($block[$property]).'$/Usi', $value) == 0) {
200
              $result .= $indent."  $property: $value;\n";
201
            }
202
          } else {
203
            $result .= "  $property: $value;\n";
204
          }
205
        }
206
        $result .= "}\n\n";
207
      }
208
    }
209
    return $result;
210
  }
211
 
212
  public function ExportStyle($index, $block = false) {
213
    $result = '';
214
    if(isset($this->cssData[$index])) {
215
      foreach($this->cssData[$index] as $media => $mediaValues) {
216
        if($media != 'all') {
217
          $result .= "@media $media {\n";
218
          $indent = '  ';
219
        } else {
220
          $indent = '';
221
        }
222
        foreach($mediaValues as $section => $sectionValues) {
223
          $result .= $indent."$section {\n";
224
          foreach($sectionValues as $property => $value) {
225
            $property = preg_replace('/(\[[0-9]*\])$/Usi', '', $property);
226
            if(is_array($block) && isset($block[$property])) {
227
              if(preg_match('/^'.static::ConvertWildcards($block[$property]).'$/Usi', $value) == 0) {
228
                $result .= $indent."  $property: $value;\n";
229
              }
230
            } else {
231
              $result .= $indent."  $property: $value;\n";
232
            }
233
          }
234
          $result .= $indent."}\n\n";
235
        }
236
        if($media != 'all') {
237
          $result .= "}\n\n";
238
        }
239
      }
240
    }
241
    return $result;
242
  }
243
 
244
 
245
  public function GetSections($index, $media = 'screen') {
246
    if(isset($this->cssData[$index])) {
247
      if(isset($this->cssData[$index][$media])) {
248
        return array_keys($this->cssData[$index][$media]);
249
      }
250
      if(isset($this->cssData[$index]['all'])) {
251
        return array_keys($this->cssData[$index]['all']);
252
      }
253
    }
254
    return false;
255
  }
256
 
257
  public function GetSectionsFiltered($index, $matchKey, $matchValue, $media = 'screen') {
258
    if(isset($this->cssData[$index])) {
259
      if(!isset($this->cssData[$index][$media])) {
260
        $media = 'all';
261
        if(!isset($this->cssData[$index][$media])) {
262
          return false;
263
        }
264
      }
265
      if(is_array($this->cssData[$index][$media])) {
266
        $result = array();
267
        foreach($this->cssData[$index][$media] as $section => $values) {
268
          if(isset($values[$matchKey])) {
269
            if($values[$matchKey] == $matchValue) {
270
              $result[] = $section;
271
            }
272
          }
273
        }
274
        return $result;
275
      }
276
    }
277
    return false;
278
  }
279
 
280
  public function GetEditorCSS($index) {
281
    $forbiddenKeys = array();
282
    $forbiddenKeys[] = '^filter$';
283
    return $this->GetCSS($index, 'screen', $forbiddenKeys);
284
  }
285
 
286
  public function GetCSS($index, $media = 'screen', $forbiddenKeys = array()) {
287
    if(isset($this->cssData[$index])) {
288
      if(!isset($this->cssData[$index][$media])) {
289
        $media = 'all';
290
        if(!isset($this->cssData[$index][$media])) {
291
          return false;
292
        }
293
      }
294
      if(is_array($this->cssData[$index][$media])) {
295
        $result = '';
296
        foreach($this->cssData[$index][$media] as $section => $values) {
297
          $result .= $section.' {';
298
          $result .= "\n";
299
          if(is_array($values)) {
300
            foreach($values as $key => $value) {
301
              $skipThis = false;
302
              foreach($forbiddenKeys as $fKey) {
303
                if(preg_match('/'.$fKey.'/Usi', $key)) {
304
                  $skipThis = true;
305
                  break;
306
                }
307
              }
308
              if($skipThis) {
309
                continue;
310
              }
311
              $result .= '  ';
312
              $key = preg_replace('/(\[[0-9]*\])$/Usi', '', $key);
313
              $result .= $key.': '.$value.';';
314
              $result .= "\n";
315
            }
316
          }
317
          $result .= '}';
318
          $result .= "\n";
319
        }
320
        return $result;
321
      }
322
    }
323
    return false;
324
  }
325
 
326
  public function GetCSSFiltered($index, $matchKey, $matchValue, $media = 'screen') {
327
    if(!isset($this->cssData[$index])) {
328
      if(!isset($this->cssData[$index][$media])) {
329
        $media = 'all';
330
        if(!isset($this->cssData[$index][$media])) {
331
          return false;
332
        }
333
      }
334
    }
335
    $sections = $this->GetSectionsFiltered($index, $matchKey, $matchValue, $media);
336
    if($sections !== false) {
337
      if(is_array($sections)) {
338
        $result = '';
339
        foreach($sections as $section) {
340
          $result .= $section.' {';
341
          $temp = $this->cssData[$index][$media];
342
          if(is_array($temp)) {
343
            foreach($temp as $key => $value) {
344
              $key = preg_replace('/(\[[0-9]*\])$/Usi', '', $key);
345
              $result .= $key.': '.$value.';';
346
            }
347
          }
348
          $result .= $section.' }';
349
        }
350
        return $result;
351
      }
352
    }
353
    return false;
354
  }
355
 
356
  public function GetCSSArray($index, $media = 'screen') {
357
    if(isset($this->cssData[$index])) {
358
      if(isset($this->cssData[$index][$media])) {
359
        return $this->cssData[$index][$media];
360
      } elseif(isset($this->cssData[$index]['all'])) {
361
        return $this->cssData[$index][$media];
362
      }
363
    }
364
    return false;
365
  }
366
 
367
  public static function ConvertWildcards($text) {
368
    $text = str_replace('.', '\.', $text);
369
    $text = str_replace('*', '.*', $text);
370
    $text = str_replace('?', '.', $text);
371
    return $text;
372
  }
373
}