danielebarchiesi@0
|
1 <?php
|
danielebarchiesi@0
|
2
|
danielebarchiesi@0
|
3 /*
|
danielebarchiesi@0
|
4 * @file
|
danielebarchiesi@0
|
5 * CSS filtering functions. Contains a disassembler, filter, compressor, and
|
danielebarchiesi@0
|
6 * decompressor.
|
danielebarchiesi@0
|
7 *
|
danielebarchiesi@0
|
8 * The general usage of this tool is:
|
danielebarchiesi@0
|
9 *
|
danielebarchiesi@0
|
10 * To simply filter CSS:
|
danielebarchiesi@0
|
11 * @code
|
danielebarchiesi@0
|
12 * $filtered_css = ctools_css_filter($css, TRUE);
|
danielebarchiesi@0
|
13 * @endcode
|
danielebarchiesi@0
|
14 *
|
danielebarchiesi@0
|
15 * In the above, if the second argument is TRUE, the returned CSS will
|
danielebarchiesi@0
|
16 * be compressed. Otherwise it will be returned in a well formatted
|
danielebarchiesi@0
|
17 * syntax.
|
danielebarchiesi@0
|
18 *
|
danielebarchiesi@0
|
19 * To cache unfiltered CSS in a file, which will be filtered:
|
danielebarchiesi@0
|
20 *
|
danielebarchiesi@0
|
21 * @code
|
danielebarchiesi@0
|
22 * $filename = ctools_css_cache($css, TRUE);
|
danielebarchiesi@0
|
23 * @endcode
|
danielebarchiesi@0
|
24 *
|
danielebarchiesi@0
|
25 * In the above, if the second argument is FALSE, the CSS will not be filtered.
|
danielebarchiesi@0
|
26 *
|
danielebarchiesi@0
|
27 * This file will be cached within the Drupal files system. This system cannot
|
danielebarchiesi@0
|
28 * detect when this file changes, so it is YOUR responsibility to remove and
|
danielebarchiesi@0
|
29 * re-cache this file when the CSS is changed. Your system should also contain
|
danielebarchiesi@0
|
30 * a backup method of re-generating the CSS cache in case it is removed, so
|
danielebarchiesi@0
|
31 * that it is easy to force a re-cache by simply deleting the contents of the
|
danielebarchiesi@0
|
32 * directory.
|
danielebarchiesi@0
|
33 *
|
danielebarchiesi@0
|
34 * Finally, if for some reason your application cannot store the filename
|
danielebarchiesi@0
|
35 * (which is true of Panels where the style can't force the display to
|
danielebarchiesi@0
|
36 * resave unconditionally) you can use the ctools storage mechanism. You
|
danielebarchiesi@0
|
37 * simply have to come up with a unique Id:
|
danielebarchiesi@0
|
38 *
|
danielebarchiesi@0
|
39 * @code
|
danielebarchiesi@0
|
40 * $filename = ctools_css_store($id, $css, TRUE);
|
danielebarchiesi@0
|
41 * @endcode
|
danielebarchiesi@0
|
42 *
|
danielebarchiesi@0
|
43 * Then later on:
|
danielebarchiesi@0
|
44 * @code
|
danielebarchiesi@0
|
45 * $filename = ctools_css_retrieve($id);
|
danielebarchiesi@0
|
46 * drupal_add_css($filename);
|
danielebarchiesi@0
|
47 * @endcode
|
danielebarchiesi@0
|
48 *
|
danielebarchiesi@0
|
49 * The CSS that was generated will be stored in the database, so even if the
|
danielebarchiesi@0
|
50 * file was removed the cached CSS will be used. If the CSS cache is
|
danielebarchiesi@0
|
51 * cleared you may be required to regenerate your CSS. This will normally
|
danielebarchiesi@0
|
52 * only be cleared by an administrator operation, not during normal usage.
|
danielebarchiesi@0
|
53 *
|
danielebarchiesi@0
|
54 * You may remove your stored CSS this way:
|
danielebarchiesi@0
|
55 *
|
danielebarchiesi@0
|
56 * @code
|
danielebarchiesi@0
|
57 * ctools_css_clear($id);
|
danielebarchiesi@0
|
58 * @endcode
|
danielebarchiesi@0
|
59 */
|
danielebarchiesi@0
|
60
|
danielebarchiesi@0
|
61 /**
|
danielebarchiesi@0
|
62 * Store CSS with a given id and return the filename to use.
|
danielebarchiesi@0
|
63 *
|
danielebarchiesi@0
|
64 * This function associates a piece of CSS with an id, and stores the
|
danielebarchiesi@0
|
65 * cached filename and the actual CSS for later use with
|
danielebarchiesi@0
|
66 * ctools_css_retrieve.
|
danielebarchiesi@0
|
67 */
|
danielebarchiesi@0
|
68 function ctools_css_store($id, $css, $filter = TRUE) {
|
danielebarchiesi@0
|
69 $filename = db_query('SELECT filename FROM {ctools_css_cache} WHERE cid = :cid', array(':cid' => $id))->fetchField();
|
danielebarchiesi@0
|
70 if ($filename && file_exists($filename)) {
|
danielebarchiesi@0
|
71 file_unmanaged_delete($filename);
|
danielebarchiesi@0
|
72 }
|
danielebarchiesi@0
|
73 // Remove any previous records.
|
danielebarchiesi@0
|
74 db_delete('ctools_css_cache')
|
danielebarchiesi@0
|
75 ->condition('cid', $id)
|
danielebarchiesi@0
|
76 ->execute();
|
danielebarchiesi@0
|
77
|
danielebarchiesi@0
|
78 $filename = ctools_css_cache($css, $filter);
|
danielebarchiesi@0
|
79
|
danielebarchiesi@0
|
80 db_insert('ctools_css_cache')
|
danielebarchiesi@0
|
81 ->fields(array(
|
danielebarchiesi@0
|
82 'cid' => $id,
|
danielebarchiesi@0
|
83 'filename' => $filename,
|
danielebarchiesi@0
|
84 'css' => $css,
|
danielebarchiesi@0
|
85 'filter' => intval($filter),
|
danielebarchiesi@0
|
86 ))
|
danielebarchiesi@0
|
87 ->execute();
|
danielebarchiesi@0
|
88
|
danielebarchiesi@0
|
89 return $filename;
|
danielebarchiesi@0
|
90 }
|
danielebarchiesi@0
|
91
|
danielebarchiesi@0
|
92 /**
|
danielebarchiesi@0
|
93 * Retrieve a filename associated with an id of previously cached CSS.
|
danielebarchiesi@0
|
94 *
|
danielebarchiesi@0
|
95 * This will ensure the file still exists and, if not, create it.
|
danielebarchiesi@0
|
96 */
|
danielebarchiesi@0
|
97 function ctools_css_retrieve($id) {
|
danielebarchiesi@0
|
98 $cache = db_query('SELECT * FROM {ctools_css_cache} WHERE cid = :cid', array(':cid' => $id))->fetchObject();
|
danielebarchiesi@0
|
99 if (!$cache) {
|
danielebarchiesi@0
|
100 return;
|
danielebarchiesi@0
|
101 }
|
danielebarchiesi@0
|
102
|
danielebarchiesi@0
|
103 if (!file_exists($cache->filename)) {
|
danielebarchiesi@0
|
104 $filename = ctools_css_cache($cache->css, $cache->filter);
|
danielebarchiesi@0
|
105 if ($filename != $cache->filename) {
|
danielebarchiesi@0
|
106 db_update('ctools_css_cache')
|
danielebarchiesi@0
|
107 ->fields(array('filename' => $filename))
|
danielebarchiesi@0
|
108 ->condition('cid', $id)
|
danielebarchiesi@0
|
109 ->execute();
|
danielebarchiesi@0
|
110 $cache->filename = $filename;
|
danielebarchiesi@0
|
111 }
|
danielebarchiesi@0
|
112 }
|
danielebarchiesi@0
|
113
|
danielebarchiesi@0
|
114 return $cache->filename;
|
danielebarchiesi@0
|
115 }
|
danielebarchiesi@0
|
116
|
danielebarchiesi@0
|
117 /**
|
danielebarchiesi@0
|
118 * Remove stored CSS and any associated file.
|
danielebarchiesi@0
|
119 */
|
danielebarchiesi@0
|
120 function ctools_css_clear($id) {
|
danielebarchiesi@0
|
121 $cache = db_query('SELECT * FROM {ctools_css_cache} WHERE cid = :cid', array(':cid' => $id))->fetchObject();
|
danielebarchiesi@0
|
122 if (!$cache) {
|
danielebarchiesi@0
|
123 return;
|
danielebarchiesi@0
|
124 }
|
danielebarchiesi@0
|
125
|
danielebarchiesi@0
|
126 if (file_exists($cache->filename)) {
|
danielebarchiesi@0
|
127 file_unmanaged_delete($cache->filename);
|
danielebarchiesi@0
|
128 // If we remove an existing file, there may be cached pages that refer
|
danielebarchiesi@0
|
129 // to it. We must get rid of them: FIXME same format in D7?
|
danielebarchiesi@0
|
130 cache_clear_all();
|
danielebarchiesi@0
|
131 }
|
danielebarchiesi@0
|
132
|
danielebarchiesi@0
|
133 db_delete('ctools_css_cache')
|
danielebarchiesi@0
|
134 ->condition('cid', $id)
|
danielebarchiesi@0
|
135 ->execute();
|
danielebarchiesi@0
|
136 }
|
danielebarchiesi@0
|
137
|
danielebarchiesi@0
|
138 /**
|
danielebarchiesi@0
|
139 * Write a chunk of CSS to a temporary cache file and return the file name.
|
danielebarchiesi@0
|
140 *
|
danielebarchiesi@0
|
141 * This function optionally filters the CSS (always compressed, if so) and
|
danielebarchiesi@0
|
142 * generates a unique filename based upon md5. It returns that filename that
|
danielebarchiesi@0
|
143 * can be used with drupal_add_css(). Note that as a cache file, technically
|
danielebarchiesi@0
|
144 * this file is volatile so it should be checked before it is used to ensure
|
danielebarchiesi@0
|
145 * that it exists.
|
danielebarchiesi@0
|
146 *
|
danielebarchiesi@0
|
147 * You can use file_exists() to test for the file and file_delete() to remove
|
danielebarchiesi@0
|
148 * it if it needs to be cleared.
|
danielebarchiesi@0
|
149 *
|
danielebarchiesi@0
|
150 * @param $css
|
danielebarchiesi@0
|
151 * A chunk of well-formed CSS text to cache.
|
danielebarchiesi@0
|
152 * @param $filter
|
danielebarchiesi@0
|
153 * If TRUE the css will be filtered. If FALSE the text will be cached
|
danielebarchiesi@0
|
154 * as-is.
|
danielebarchiesi@0
|
155 *
|
danielebarchiesi@0
|
156 * @return $filename
|
danielebarchiesi@0
|
157 * The filename the CSS will be cached in.
|
danielebarchiesi@0
|
158 */
|
danielebarchiesi@0
|
159 function ctools_css_cache($css, $filter = TRUE) {
|
danielebarchiesi@0
|
160 if ($filter) {
|
danielebarchiesi@0
|
161 $css = ctools_css_filter($css);
|
danielebarchiesi@0
|
162 }
|
danielebarchiesi@0
|
163
|
danielebarchiesi@0
|
164 // Create the css/ within the files folder.
|
danielebarchiesi@0
|
165 $path = 'public://ctools/css';
|
danielebarchiesi@0
|
166 if (!file_prepare_directory($path, FILE_CREATE_DIRECTORY | FILE_MODIFY_PERMISSIONS)) {
|
danielebarchiesi@0
|
167 // if (!file_prepare_directory($path, FILE_CREATE_DIRECTORY)) {
|
danielebarchiesi@0
|
168 drupal_set_message(t('Unable to create CTools CSS cache directory. Check the permissions on your files directory.'), 'error');
|
danielebarchiesi@0
|
169 return;
|
danielebarchiesi@0
|
170 }
|
danielebarchiesi@0
|
171
|
danielebarchiesi@0
|
172 // @todo Is this slow? Does it matter if it is?
|
danielebarchiesi@0
|
173 $filename = $path . '/' . md5($css) . '.css';
|
danielebarchiesi@0
|
174
|
danielebarchiesi@0
|
175 // This will do renames if the file already exists, ensuring we don't
|
danielebarchiesi@0
|
176 // accidentally overwrite other files who share the same md5. Yes this
|
danielebarchiesi@0
|
177 // is a very miniscule chance but it's safe.
|
danielebarchiesi@0
|
178 $filename = file_unmanaged_save_data($css, $filename);
|
danielebarchiesi@0
|
179
|
danielebarchiesi@0
|
180 return $filename;
|
danielebarchiesi@0
|
181 }
|
danielebarchiesi@0
|
182
|
danielebarchiesi@0
|
183 /**
|
danielebarchiesi@0
|
184 * Filter a chunk of CSS text.
|
danielebarchiesi@0
|
185 *
|
danielebarchiesi@0
|
186 * This function disassembles the CSS into a raw format that makes it easier
|
danielebarchiesi@0
|
187 * for our tool to work, then runs it through the filter and reassembles it.
|
danielebarchiesi@0
|
188 * If you find that you want the raw data for some reason or another, you
|
danielebarchiesi@0
|
189 * can use the disassemble/assemble functions yourself.
|
danielebarchiesi@0
|
190 *
|
danielebarchiesi@0
|
191 * @param $css
|
danielebarchiesi@0
|
192 * The CSS text to filter.
|
danielebarchiesi@0
|
193 * @param $compressed
|
danielebarchiesi@0
|
194 * If true, generate compressed output; if false, generate pretty output.
|
danielebarchiesi@0
|
195 * Defaults to TRUE.
|
danielebarchiesi@0
|
196 */
|
danielebarchiesi@0
|
197 function ctools_css_filter($css, $compressed = TRUE) {
|
danielebarchiesi@0
|
198 $css_data = ctools_css_disassemble($css);
|
danielebarchiesi@0
|
199
|
danielebarchiesi@0
|
200 // Note: By using this function yourself you can control the allowed
|
danielebarchiesi@0
|
201 // properties and values list.
|
danielebarchiesi@0
|
202 $filtered = ctools_css_filter_css_data($css_data);
|
danielebarchiesi@0
|
203
|
danielebarchiesi@0
|
204 return $compressed ? ctools_css_compress($filtered) : ctools_css_assemble($filtered);
|
danielebarchiesi@0
|
205 }
|
danielebarchiesi@0
|
206
|
danielebarchiesi@0
|
207 /**
|
danielebarchiesi@0
|
208 * Re-assemble a css string and format it nicely.
|
danielebarchiesi@0
|
209 *
|
danielebarchiesi@0
|
210 * @param array $css_data
|
danielebarchiesi@0
|
211 * An array of css data, as produced by @see ctools_css_disassemble()
|
danielebarchiesi@0
|
212 * disassembler and the @see ctools_css_filter_css_data() filter.
|
danielebarchiesi@0
|
213 *
|
danielebarchiesi@0
|
214 * @return string $css
|
danielebarchiesi@0
|
215 * css optimized for human viewing.
|
danielebarchiesi@0
|
216 */
|
danielebarchiesi@0
|
217 function ctools_css_assemble($css_data) {
|
danielebarchiesi@0
|
218 // Initialize the output.
|
danielebarchiesi@0
|
219 $css = '';
|
danielebarchiesi@0
|
220 // Iterate through all the statements.
|
danielebarchiesi@0
|
221 foreach ($css_data as $selector_str => $declaration) {
|
danielebarchiesi@0
|
222 // Add the selectors, separating them with commas and line feeds.
|
danielebarchiesi@0
|
223 $css .= strpos($selector_str, ',') === FALSE ? $selector_str : str_replace(", ", ",\n", $selector_str);
|
danielebarchiesi@0
|
224 // Add the opening curly brace.
|
danielebarchiesi@0
|
225 $css .= " {\n";
|
danielebarchiesi@0
|
226 // Iterate through all the declarations.
|
danielebarchiesi@0
|
227 foreach ($declaration as $property => $value) {
|
danielebarchiesi@0
|
228 $css .= " " . $property . ": " . $value . ";\n";
|
danielebarchiesi@0
|
229 }
|
danielebarchiesi@0
|
230 // Add the closing curly brace.
|
danielebarchiesi@0
|
231 $css .= "}\n\n";
|
danielebarchiesi@0
|
232 }
|
danielebarchiesi@0
|
233 // Return the output.
|
danielebarchiesi@0
|
234 return $css;
|
danielebarchiesi@0
|
235 }
|
danielebarchiesi@0
|
236
|
danielebarchiesi@0
|
237 /**
|
danielebarchiesi@0
|
238 * Compress css data (filter it first!) to optimize for use on view.
|
danielebarchiesi@0
|
239 *
|
danielebarchiesi@0
|
240 * @param array $css_data
|
danielebarchiesi@0
|
241 * An array of css data, as produced by @see ctools_css_disassemble()
|
danielebarchiesi@0
|
242 * disassembler and the @see ctools_css_filter_css_data() filter.
|
danielebarchiesi@0
|
243 *
|
danielebarchiesi@0
|
244 * @return string $css
|
danielebarchiesi@0
|
245 * css optimized for use.
|
danielebarchiesi@0
|
246 */
|
danielebarchiesi@0
|
247 function ctools_css_compress($css_data) {
|
danielebarchiesi@0
|
248 // Initialize the output.
|
danielebarchiesi@0
|
249 $css = '';
|
danielebarchiesi@0
|
250 // Iterate through all the statements.
|
danielebarchiesi@0
|
251 foreach ($css_data as $selector_str => $declaration) {
|
danielebarchiesi@0
|
252 if (empty($declaration)) {
|
danielebarchiesi@0
|
253 // Skip this statement if filtering removed all parts of the declaration.
|
danielebarchiesi@0
|
254 continue;
|
danielebarchiesi@0
|
255 }
|
danielebarchiesi@0
|
256 // Add the selectors, separating them with commas.
|
danielebarchiesi@0
|
257 $css .= $selector_str;
|
danielebarchiesi@0
|
258 // And, the opening curly brace.
|
danielebarchiesi@0
|
259 $css .= "{";
|
danielebarchiesi@0
|
260 // Iterate through all the statement properties.
|
danielebarchiesi@0
|
261 foreach ($declaration as $property => $value) {
|
danielebarchiesi@0
|
262 $css .= $property . ':' . $value . ';';
|
danielebarchiesi@0
|
263 }
|
danielebarchiesi@0
|
264 // Add the closing curly brace.
|
danielebarchiesi@0
|
265 $css .= "}";
|
danielebarchiesi@0
|
266 }
|
danielebarchiesi@0
|
267 // Return the output.
|
danielebarchiesi@0
|
268 return $css;
|
danielebarchiesi@0
|
269 }
|
danielebarchiesi@0
|
270
|
danielebarchiesi@0
|
271 /**
|
danielebarchiesi@0
|
272 * Disassemble the css string.
|
danielebarchiesi@0
|
273 *
|
danielebarchiesi@0
|
274 * Strip the css of irrelevant characters, invalid/malformed selectors and
|
danielebarchiesi@0
|
275 * declarations, and otherwise prepare it for processing.
|
danielebarchiesi@0
|
276 *
|
danielebarchiesi@0
|
277 * @param string $css
|
danielebarchiesi@0
|
278 * A string containing the css to be disassembled.
|
danielebarchiesi@0
|
279 *
|
danielebarchiesi@0
|
280 * @return array $disassembled_css
|
danielebarchiesi@0
|
281 * An array of disassembled, slightly cleaned-up/formatted css statements.
|
danielebarchiesi@0
|
282 */
|
danielebarchiesi@0
|
283 function ctools_css_disassemble($css) {
|
danielebarchiesi@0
|
284 $disassembled_css = array();
|
danielebarchiesi@0
|
285 // Remove comments.
|
danielebarchiesi@0
|
286 $css = preg_replace("/\/\*(.*)?\*\//Usi", "", $css);
|
danielebarchiesi@0
|
287 // Split out each statement. Match either a right curly brace or a semi-colon
|
danielebarchiesi@0
|
288 // that precedes a left curly brace with no right curly brace separating them.
|
danielebarchiesi@0
|
289 $statements = preg_split('/}|;(?=[^}]*{)/', $css);
|
danielebarchiesi@0
|
290
|
danielebarchiesi@0
|
291 // If we have any statements, parse them.
|
danielebarchiesi@0
|
292 if (!empty($statements)) {
|
danielebarchiesi@0
|
293 // Iterate through all of the statements.
|
danielebarchiesi@0
|
294 foreach ($statements as $statement) {
|
danielebarchiesi@0
|
295 // Get the selector(s) and declaration.
|
danielebarchiesi@0
|
296 if (empty($statement) || !strpos($statement, '{')) {
|
danielebarchiesi@0
|
297 continue;
|
danielebarchiesi@0
|
298 }
|
danielebarchiesi@0
|
299
|
danielebarchiesi@0
|
300 list($selector_str, $declaration) = explode('{', $statement);
|
danielebarchiesi@0
|
301
|
danielebarchiesi@0
|
302 // If the selector exists, then disassemble it, check it, and regenerate
|
danielebarchiesi@0
|
303 // the selector string.
|
danielebarchiesi@0
|
304 $selector_str = empty($selector_str) ? FALSE : _ctools_css_disassemble_selector($selector_str);
|
danielebarchiesi@0
|
305 if (empty($selector_str)) {
|
danielebarchiesi@0
|
306 // No valid selectors. Bomb out and start the next item.
|
danielebarchiesi@0
|
307 continue;
|
danielebarchiesi@0
|
308 }
|
danielebarchiesi@0
|
309
|
danielebarchiesi@0
|
310 // Disassemble the declaration, check it and tuck it into an array.
|
danielebarchiesi@0
|
311 if (!isset($disassembled_css[$selector_str])) {
|
danielebarchiesi@0
|
312 $disassembled_css[$selector_str] = array();
|
danielebarchiesi@0
|
313 }
|
danielebarchiesi@0
|
314 $disassembled_css[$selector_str] += _ctools_css_disassemble_declaration($declaration);
|
danielebarchiesi@0
|
315 }
|
danielebarchiesi@0
|
316 }
|
danielebarchiesi@0
|
317 return $disassembled_css;
|
danielebarchiesi@0
|
318 }
|
danielebarchiesi@0
|
319
|
danielebarchiesi@0
|
320 function _ctools_css_disassemble_selector($selector_str) {
|
danielebarchiesi@0
|
321 // Get all selectors individually.
|
danielebarchiesi@0
|
322 $selectors = explode(",", trim($selector_str));
|
danielebarchiesi@0
|
323 // Iterate through all the selectors, sanity check them and return if they
|
danielebarchiesi@0
|
324 // pass. Note that this handles 0, 1, or more valid selectors gracefully.
|
danielebarchiesi@0
|
325 foreach ($selectors as $key => $selector) {
|
danielebarchiesi@0
|
326 // Replace un-needed characters and do a little cleanup.
|
danielebarchiesi@0
|
327 $selector = preg_replace("/[\n|\t|\\|\s]+/", ' ', trim($selector));
|
danielebarchiesi@0
|
328 // Make sure this is still a real selector after cleanup.
|
danielebarchiesi@0
|
329 if (!empty($selector)) {
|
danielebarchiesi@0
|
330 $selectors[$key] = $selector;
|
danielebarchiesi@0
|
331 }
|
danielebarchiesi@0
|
332 else {
|
danielebarchiesi@0
|
333 // Selector is no good, so we scrap it.
|
danielebarchiesi@0
|
334 unset($selectors[$key]);
|
danielebarchiesi@0
|
335 }
|
danielebarchiesi@0
|
336 }
|
danielebarchiesi@0
|
337 // Check for malformed selectors; if found, we skip this declaration.
|
danielebarchiesi@0
|
338 if (empty($selectors)) {
|
danielebarchiesi@0
|
339 return FALSE;
|
danielebarchiesi@0
|
340 }
|
danielebarchiesi@0
|
341 return implode(', ', $selectors);
|
danielebarchiesi@0
|
342 }
|
danielebarchiesi@0
|
343
|
danielebarchiesi@0
|
344 function _ctools_css_disassemble_declaration($declaration) {
|
danielebarchiesi@0
|
345 $formatted_statement = array();
|
danielebarchiesi@0
|
346 $propval_pairs = explode(";", $declaration);
|
danielebarchiesi@0
|
347 // Make sure we actually have some properties to work with.
|
danielebarchiesi@0
|
348 if (!empty($propval_pairs)) {
|
danielebarchiesi@0
|
349 // Iterate through the remains and parse them.
|
danielebarchiesi@0
|
350 foreach ($propval_pairs as $key => $propval_pair) {
|
danielebarchiesi@0
|
351 // Check that we have a ':', otherwise it's an invalid pair.
|
danielebarchiesi@0
|
352 if (strpos($propval_pair, ':') === FALSE) {
|
danielebarchiesi@0
|
353 continue;
|
danielebarchiesi@0
|
354 }
|
danielebarchiesi@0
|
355 // Clean up the current property-value pair.
|
danielebarchiesi@0
|
356 $propval_pair = preg_replace("/[\n|\t|\\|\s]+/", ' ', trim($propval_pair));
|
danielebarchiesi@0
|
357 // Explode the remaining fragements some more, but clean them up first.
|
danielebarchiesi@0
|
358 list($property, $value) = explode(':', $propval_pair, 2);
|
danielebarchiesi@0
|
359 // If the property survived, toss it onto the stack.
|
danielebarchiesi@0
|
360 if (!empty($property)) {
|
danielebarchiesi@0
|
361 $formatted_statement[trim($property)] = trim($value);
|
danielebarchiesi@0
|
362 }
|
danielebarchiesi@0
|
363 }
|
danielebarchiesi@0
|
364 }
|
danielebarchiesi@0
|
365 return $formatted_statement;
|
danielebarchiesi@0
|
366 }
|
danielebarchiesi@0
|
367
|
danielebarchiesi@0
|
368 /**
|
danielebarchiesi@0
|
369 * Run disassembled $css through the filter.
|
danielebarchiesi@0
|
370 *
|
danielebarchiesi@0
|
371 * @param $css
|
danielebarchiesi@0
|
372 * CSS code disassembled by ctools_dss_disassemble().
|
danielebarchiesi@0
|
373 * @param $allowed_properties
|
danielebarchiesi@0
|
374 * A list of properties that are allowed by the filter. If empty
|
danielebarchiesi@0
|
375 * ctools_css_filter_default_allowed_properties() will provide the
|
danielebarchiesi@0
|
376 * list.
|
danielebarchiesi@0
|
377 * @param $allowed_values
|
danielebarchiesi@0
|
378 * A list of values that are allowed by the filter. If empty
|
danielebarchiesi@0
|
379 * ctools_css_filter_default_allowed_values() will provide the
|
danielebarchiesi@0
|
380 * list.
|
danielebarchiesi@0
|
381 *
|
danielebarchiesi@0
|
382 * @return
|
danielebarchiesi@0
|
383 * An array of disassembled, filtered CSS.
|
danielebarchiesi@0
|
384 */
|
danielebarchiesi@0
|
385 function ctools_css_filter_css_data($css, $allowed_properties = array(), $allowed_values = array(), $allowed_values_regex = '', $disallowed_values_regex = '') {
|
danielebarchiesi@0
|
386 //function ctools_css_filter_css_data($css, &$filtered = NULL, $allowed_properties = array(), $allowed_values = array(), $allowed_values_regex = '', $disallowed_values_regex = '') {
|
danielebarchiesi@0
|
387 // Retrieve the default list of allowed properties if none is provided.
|
danielebarchiesi@0
|
388 $allowed_properties = !empty($allowed_properties) ? $allowed_properties : ctools_css_filter_default_allowed_properties();
|
danielebarchiesi@0
|
389 // Retrieve the default list of allowed values if none is provided.
|
danielebarchiesi@0
|
390 $allowed_values = !empty($allowed_values) ? $allowed_values : ctools_css_filter_default_allowed_values();
|
danielebarchiesi@0
|
391 // Define allowed values regex if none is provided.
|
danielebarchiesi@0
|
392 $allowed_values_regex = !empty($allowed_values_regex) ? $allowed_values_regex : '/(#[0-9a-f]+|rgb\(\d+%?,\d*%?,?\d*%?\)?|\d{0,2}\.?\d{0,2}(cm|em|ex|in|mm|pc|pt|px|%|,|\))?)/';
|
danielebarchiesi@0
|
393 // Define disallowed url() value contents, if none is provided.
|
danielebarchiesi@0
|
394 // $disallowed_values_regex = !empty($disallowed_values_regex) ? $disallowed_values_regex : '/[url|expression]\s*\(\s*[^\s)]+?\s*\)\s*/';
|
danielebarchiesi@0
|
395 $disallowed_values_regex = !empty($disallowed_values_regex) ? $disallowed_values_regex : '/(url|expression)/';
|
danielebarchiesi@0
|
396
|
danielebarchiesi@0
|
397 foreach ($css as $selector_str => $declaration) {
|
danielebarchiesi@0
|
398 foreach ($declaration as $property => $value) {
|
danielebarchiesi@0
|
399 if (!in_array($property, $allowed_properties)) {
|
danielebarchiesi@0
|
400 // $filtered['properties'][$selector_str][$property] = $value;
|
danielebarchiesi@0
|
401 unset($css[$selector_str][$property]);
|
danielebarchiesi@0
|
402 continue;
|
danielebarchiesi@0
|
403 }
|
danielebarchiesi@0
|
404 $value = str_replace('!important', '', $value);
|
danielebarchiesi@0
|
405 if (preg_match($disallowed_values_regex, $value) || !(in_array($value, $allowed_values) || preg_match($allowed_values_regex, $value))) {
|
danielebarchiesi@0
|
406 // $filtered['values'][$selector_str][$property] = $value;
|
danielebarchiesi@0
|
407 unset($css[$selector_str][$property]);
|
danielebarchiesi@0
|
408 continue;
|
danielebarchiesi@0
|
409 }
|
danielebarchiesi@0
|
410 }
|
danielebarchiesi@0
|
411 }
|
danielebarchiesi@0
|
412 return $css;
|
danielebarchiesi@0
|
413 }
|
danielebarchiesi@0
|
414
|
danielebarchiesi@0
|
415 /**
|
danielebarchiesi@0
|
416 * Provide a deafult list of allowed properties by the filter.
|
danielebarchiesi@0
|
417 */
|
danielebarchiesi@0
|
418 function ctools_css_filter_default_allowed_properties() {
|
danielebarchiesi@0
|
419 return array(
|
danielebarchiesi@0
|
420 'azimuth',
|
danielebarchiesi@0
|
421 'background',
|
danielebarchiesi@0
|
422 'background-color',
|
danielebarchiesi@0
|
423 'background-image',
|
danielebarchiesi@0
|
424 'background-repeat',
|
danielebarchiesi@0
|
425 'background-attachment',
|
danielebarchiesi@0
|
426 'background-position',
|
danielebarchiesi@0
|
427 'border',
|
danielebarchiesi@0
|
428 'border-top-width',
|
danielebarchiesi@0
|
429 'border-right-width',
|
danielebarchiesi@0
|
430 'border-bottom-width',
|
danielebarchiesi@0
|
431 'border-left-width',
|
danielebarchiesi@0
|
432 'border-width',
|
danielebarchiesi@0
|
433 'border-top-color',
|
danielebarchiesi@0
|
434 'border-right-color',
|
danielebarchiesi@0
|
435 'border-bottom-color',
|
danielebarchiesi@0
|
436 'border-left-color',
|
danielebarchiesi@0
|
437 'border-color',
|
danielebarchiesi@0
|
438 'border-top-style',
|
danielebarchiesi@0
|
439 'border-right-style',
|
danielebarchiesi@0
|
440 'border-bottom-style',
|
danielebarchiesi@0
|
441 'border-left-style',
|
danielebarchiesi@0
|
442 'border-style',
|
danielebarchiesi@0
|
443 'border-top',
|
danielebarchiesi@0
|
444 'border-right',
|
danielebarchiesi@0
|
445 'border-bottom',
|
danielebarchiesi@0
|
446 'border-left',
|
danielebarchiesi@0
|
447 'clear',
|
danielebarchiesi@0
|
448 'color',
|
danielebarchiesi@0
|
449 'cursor',
|
danielebarchiesi@0
|
450 'direction',
|
danielebarchiesi@0
|
451 'display',
|
danielebarchiesi@0
|
452 'elevation',
|
danielebarchiesi@0
|
453 'float',
|
danielebarchiesi@0
|
454 'font',
|
danielebarchiesi@0
|
455 'font-family',
|
danielebarchiesi@0
|
456 'font-size',
|
danielebarchiesi@0
|
457 'font-style',
|
danielebarchiesi@0
|
458 'font-variant',
|
danielebarchiesi@0
|
459 'font-weight',
|
danielebarchiesi@0
|
460 'height',
|
danielebarchiesi@0
|
461 'letter-spacing',
|
danielebarchiesi@0
|
462 'line-height',
|
danielebarchiesi@0
|
463 'margin',
|
danielebarchiesi@0
|
464 'margin-top',
|
danielebarchiesi@0
|
465 'margin-right',
|
danielebarchiesi@0
|
466 'margin-bottom',
|
danielebarchiesi@0
|
467 'margin-left',
|
danielebarchiesi@0
|
468 'overflow',
|
danielebarchiesi@0
|
469 'padding',
|
danielebarchiesi@0
|
470 'padding-top',
|
danielebarchiesi@0
|
471 'padding-right',
|
danielebarchiesi@0
|
472 'padding-bottom',
|
danielebarchiesi@0
|
473 'padding-left',
|
danielebarchiesi@0
|
474 'pause',
|
danielebarchiesi@0
|
475 'pause-after',
|
danielebarchiesi@0
|
476 'pause-before',
|
danielebarchiesi@0
|
477 'pitch',
|
danielebarchiesi@0
|
478 'pitch-range',
|
danielebarchiesi@0
|
479 'richness',
|
danielebarchiesi@0
|
480 'speak',
|
danielebarchiesi@0
|
481 'speak-header',
|
danielebarchiesi@0
|
482 'speak-numeral',
|
danielebarchiesi@0
|
483 'speak-punctuation',
|
danielebarchiesi@0
|
484 'speech-rate',
|
danielebarchiesi@0
|
485 'stress',
|
danielebarchiesi@0
|
486 'text-align',
|
danielebarchiesi@0
|
487 'text-decoration',
|
danielebarchiesi@0
|
488 'text-indent',
|
danielebarchiesi@0
|
489 'text-transform',
|
danielebarchiesi@0
|
490 'unicode-bidi',
|
danielebarchiesi@0
|
491 'vertical-align',
|
danielebarchiesi@0
|
492 'voice-family',
|
danielebarchiesi@0
|
493 'volume',
|
danielebarchiesi@0
|
494 'white-space',
|
danielebarchiesi@0
|
495 'width',
|
danielebarchiesi@0
|
496 'fill',
|
danielebarchiesi@0
|
497 'fill-opacity',
|
danielebarchiesi@0
|
498 'fill-rule',
|
danielebarchiesi@0
|
499 'stroke',
|
danielebarchiesi@0
|
500 'stroke-width',
|
danielebarchiesi@0
|
501 'stroke-linecap',
|
danielebarchiesi@0
|
502 'stroke-linejoin',
|
danielebarchiesi@0
|
503 'stroke-opacity',
|
danielebarchiesi@0
|
504 );
|
danielebarchiesi@0
|
505 }
|
danielebarchiesi@0
|
506
|
danielebarchiesi@0
|
507 /**
|
danielebarchiesi@0
|
508 * Provide a default list of allowed values by the filter.
|
danielebarchiesi@0
|
509 */
|
danielebarchiesi@0
|
510 function ctools_css_filter_default_allowed_values() {
|
danielebarchiesi@0
|
511 return array(
|
danielebarchiesi@0
|
512 'auto',
|
danielebarchiesi@0
|
513 'aqua',
|
danielebarchiesi@0
|
514 'black',
|
danielebarchiesi@0
|
515 'block',
|
danielebarchiesi@0
|
516 'blue',
|
danielebarchiesi@0
|
517 'bold',
|
danielebarchiesi@0
|
518 'both',
|
danielebarchiesi@0
|
519 'bottom',
|
danielebarchiesi@0
|
520 'brown',
|
danielebarchiesi@0
|
521 'capitalize',
|
danielebarchiesi@0
|
522 'center',
|
danielebarchiesi@0
|
523 'collapse',
|
danielebarchiesi@0
|
524 'dashed',
|
danielebarchiesi@0
|
525 'dotted',
|
danielebarchiesi@0
|
526 'fuchsia',
|
danielebarchiesi@0
|
527 'gray',
|
danielebarchiesi@0
|
528 'green',
|
danielebarchiesi@0
|
529 'italic',
|
danielebarchiesi@0
|
530 'inherit',
|
danielebarchiesi@0
|
531 'left',
|
danielebarchiesi@0
|
532 'lime',
|
danielebarchiesi@0
|
533 'lowercase',
|
danielebarchiesi@0
|
534 'maroon',
|
danielebarchiesi@0
|
535 'medium',
|
danielebarchiesi@0
|
536 'navy',
|
danielebarchiesi@0
|
537 'normal',
|
danielebarchiesi@0
|
538 'nowrap',
|
danielebarchiesi@0
|
539 'olive',
|
danielebarchiesi@0
|
540 'pointer',
|
danielebarchiesi@0
|
541 'purple',
|
danielebarchiesi@0
|
542 'red',
|
danielebarchiesi@0
|
543 'right',
|
danielebarchiesi@0
|
544 'solid',
|
danielebarchiesi@0
|
545 'silver',
|
danielebarchiesi@0
|
546 'teal',
|
danielebarchiesi@0
|
547 'top',
|
danielebarchiesi@0
|
548 'transparent',
|
danielebarchiesi@0
|
549 'underline',
|
danielebarchiesi@0
|
550 'uppercase',
|
danielebarchiesi@0
|
551 'white',
|
danielebarchiesi@0
|
552 'yellow',
|
danielebarchiesi@0
|
553 );
|
danielebarchiesi@0
|
554 }
|
danielebarchiesi@0
|
555
|
danielebarchiesi@0
|
556 /**
|
danielebarchiesi@0
|
557 * Delegated implementation of hook_flush_caches()
|
danielebarchiesi@0
|
558 */
|
danielebarchiesi@0
|
559 function ctools_css_flush_caches() {
|
danielebarchiesi@0
|
560 // Remove all generated files.
|
danielebarchiesi@0
|
561 // @see http://drupal.org/node/573292
|
danielebarchiesi@0
|
562 // file_unmanaged_delete_recursive('public://render');
|
danielebarchiesi@0
|
563 $filedir = file_default_scheme() . '://ctools/css';
|
danielebarchiesi@0
|
564 if (drupal_realpath($filedir) && file_exists($filedir)) {
|
danielebarchiesi@0
|
565 // We use the @ because it's possible that files created by the webserver
|
danielebarchiesi@0
|
566 // cannot be deleted while using drush to clear the cache. We don't really
|
danielebarchiesi@0
|
567 // care that much about that, to be honest, so we use the @ to suppress
|
danielebarchiesi@0
|
568 // the error message.
|
danielebarchiesi@0
|
569 @file_unmanaged_delete_recursive($filedir);
|
danielebarchiesi@0
|
570 }
|
danielebarchiesi@0
|
571
|
danielebarchiesi@0
|
572 db_delete('ctools_css_cache')->execute();
|
danielebarchiesi@0
|
573 }
|