/[drupal]/contributions/modules/cssapi/cssapi.module
ViewVC logotype

Contents of /contributions/modules/cssapi/cssapi.module

Parent Directory Parent Directory | Revision Log Revision Log | View Revision Graph Revision Graph


Revision 1.1 - (show annotations) (download) (as text)
Mon Aug 4 14:22:10 2008 UTC (15 months, 3 weeks ago) by jjeff
Branch: MAIN
CVS Tags: DRUPAL-6--0-5-alpha, HEAD
File MIME type: text/x-php
Initial CSS API module. Provides functions for editing/replacing/removing CSS files
1 <?php
2 // $Id:$
3
4 /**
5 @TODO
6 - check that the files/dcss directory...
7 */
8
9
10 // **************************************************************************
11 // CONSTANTS **************************************************************
12 // **************************************************************************
13
14 /**
15 * These define the various types of overrides for a given sheet
16 */
17
18 define('CSS_NORMAL', 0);
19 define('CSS_REMOVED', 1);
20 define('CSS_EDITABLE', 2);
21 define('CSS_ADDED', 3); // currently unused
22
23 /**
24 * @NOTES
25 * variables set:
26 * - cssapi_css_list_{$theme} - the listing of all CSS files "seen" with this theme enabled
27 * - cssapi_overrides_{$theme} - the list of overridden files - key is path, val is type
28 */
29
30
31 // **************************************************************************
32 // HOOKS ******************************************************************
33 // **************************************************************************
34
35 /**
36 * Implementation of hook_preprocess_page
37 *
38 * Note that we're using hook_theme_registry_alter() to
39 * run this AFTER the theme's preprocess_page function
40 */
41 function cssapi_preprocess_page(&$vars) {
42 $theme = $GLOBALS['theme'];
43 $overrides = variable_get('cssapi_overrides_'. $theme, array());
44 $known_css = variable_get('cssapi_css_list_'. $theme, array());
45 $new_css = $known_css;
46 $old_files = array();
47 $altered = FALSE;
48 // go through all of the css files added to the page and see if there are overrides
49 foreach ($vars['css'] as $media => $types) {
50 foreach ($vars['css'][$media] as $type => $files) {
51 foreach (array_keys($files) as $file) {
52 if (!in_array($file, $known_css)) {
53 // if we've found a new CSS file, add it to the list
54 $new_css[] = $file;
55 }
56 // see if this file is overridden
57 if (isset($overrides[$file])) {
58 $altered = TRUE;
59 switch ($overrides[$file]) {
60
61 case CSS_REMOVED :
62 // remove it
63 unset($vars['css'][$media][$type][$file]);
64 break;
65
66 case CSS_EDITABLE :
67 // swap out for the edited version
68 // grrr.... I really wish there were a way to edit/remove the static $css variable inside of drupal_add_css()
69 $replacement = cssapi_get_editable_path($file, $theme, TRUE);
70 if ($replacement) {
71 // this next line causes CSS to NOT aggregate for users with 'display CSS' permissions
72 $vars['css'][$media][$type][$replacement] = user_access('display CSS') ? 0 : $vars['css'][$media][$type][$file];
73 //$old_files['css'][$media][$type][$replacement] = $file;
74
75 // store a relationship between the old file name and the new (md5 hash version)
76 $pattern = '/([^\/]*?\.css)/i';
77 preg_match($pattern, $replacement, $rep_matches);
78 preg_match($pattern, $file, $orig_matches);
79 $css_map[$rep_matches[1]] = $orig_matches[1];
80
81 unset($vars['css'][$media][$type][$file]);
82 }
83 break;
84 }
85 }
86 }
87 }
88 }
89 // if we've found new css files, re-create the css_list variable
90 if (count($known_css) != count($new_css)) {
91 variable_set('cssapi_css_list_'. $theme, $new_css);
92 }
93 if ($altered) {
94 $vars['styles'] = drupal_get_css($vars['css']);
95 }
96 if (user_access('display CSS')) {
97 if (!empty($overrides)) {
98 drupal_add_js(array('cssapi' => array('css' => $css_map)), 'setting');
99 // $vars['scripts'] = drupal_get_js();
100 }
101 }
102 }
103
104 /**
105 * An implementation of hook_theme_registry_alter()
106 *
107 * Alter the theme registry so that cssapi_preprocess_page runs after theme_preprocess_page.
108 *
109 * @return void
110 **/
111 function cssapi_theme_registry_alter(&$theme_registry) {
112 // we want to run cssapi_preprocess_page AFTER the theme's _preprocess_page
113 if (isset($theme_registry['page'])) {
114 if ($key = array_search('cssapi_preprocess_page', $theme_registry['page']['preprocess functions'])) {
115 unset($theme_registry['page']['preprocess functions'][$key]);
116 }
117 // now tack it on the end
118 $theme_registry['page']['preprocess functions'][] = 'cssapi_preprocess_page';
119 }
120
121 // we're going to also take this opportunity to reset the "cache" of seen CSS files
122 //variable_set('cssapi_css_list_'. $theme, array());
123 }
124
125 // **************************************************************************
126 // UTILITY/API FUNCTIONS **************************************************
127 // **************************************************************************
128
129 // *********************************************
130 // FULL SHEET FUNCTIONS **********************
131 // *********************************************
132
133 function cssapi_all_styles($theme) {
134 return variable_get('cssapi_css_list_'. $theme, array());
135 }
136
137 /**
138 * Save new overrides
139
140 @TODO this function could/should copy styles into files dir
141
142 *
143 * @param $overrides
144 * An array of overrides where the keys are the path to the
145 * non-editable CSS file and the values are the type of override.
146 * example: array('modules/system/system.css' => CSS_REMOVED)
147 * This can also be used to simultaneously 'remove' overrides
148 * by setting to CSS_NORMAL
149 *
150 * @param $theme
151 * The name of the theme being affected
152 *
153 * @return
154 * The new overrides
155 */
156 function cssapi_save_overrides($overrides, $theme) {
157 $current = variable_get('cssapi_overrides_'. $theme, array());
158 // merge in the new overrides
159 $new = array_merge($current, $overrides);
160 variable_set('cssapi_overrides_'. $theme, $new);
161 return $new;
162 }
163
164 /**
165 * Remove overrides
166 *
167 * @param $overrides
168 * An array of paths to non-editable CSS files which will
169 * no longer be overridden.
170 * example: array('modules/system/system.css')
171 *
172 * @param $theme
173 * The name of the the theme being affected
174 */
175 function cssapi_remove_overrides($overrides, $theme) {
176 $current = variable_get('cssapi_overrides_'. $theme, array());
177 if (is_array($overrides)) {
178 foreach($overrides as $override) {
179 unset($current[$override]);
180 }
181 }
182 variable_set('cssapi_overrides_'. $theme, $current);
183 }
184
185 function cssapi_load_overrides($theme) {
186 return variable_get('cssapi_overrides_'. $theme, array());
187 }
188
189 /**
190 * Save new additions
191 *
192 * @param $additions
193 * An array of additions where the keys are the unique name
194 * of the override and the values are the path to the CSS
195 * THIS IS DIFFERENT THAN THE OVERRIDES FORMAT
196 * example: array('my_addition' => 'default/files/dcss/bd9rlitbl84.css')
197 * This can also be used to simultaneously 'remove' overrides
198 * by setting to CSS_NORMAL
199 *
200 * @param $theme
201 * The name of the theme being affected
202 *
203 * @return
204 * The new overrides
205 */
206 function cssapi_save_additions($additions, $theme) {
207 $current = variable_get('cssapi_additions_'. $theme, array());
208 $new = array_merge($current, $additions);
209 variable_set('cssapi_additions_' . $theme, $new);
210 return $new;
211 }
212
213 function cssapi_remove_additions($additions, $theme) {
214 $current = variable_get('cssapi_additions_'. $theme, array());
215 if (is_array($overrides)) {
216 foreach($additions as $addition) {
217 unset($current[$addition]);
218 }
219 }
220 variable_set('cssapi_additions_'. $theme, $current);
221 }
222
223 function cssapi_load_additions($theme) {
224 return variable_get('cssapi_additions_'. $theme, array());
225 }
226
227
228 /**
229 * Save a style sheet
230 *
231 * @param $content The content of the style sheet to be saved
232 * @param $sheet The md5 hashed name of the style sheet - example: md5($theme .'/'. $path_to_orig_sheet)
233 */
234 function cssapi_save_sheet($content, $sheet) {
235 // Create/confirm dcss/ within the files folder.
236 $cssdir = file_create_path(variable_get('cssapi_dir', 'dcss'));
237 file_check_directory($cssdir, FILE_CREATE_DIRECTORY);
238
239 // save the file
240 file_save_data($content, $sheet, FILE_EXISTS_REPLACE);
241 // save to the database
242 $revision->content = $content;
243 $revision->sheet = $sheet;
244 $revision->timestamp = time();
245 drupal_write_record('cssapi', $revision);
246 // flush the css cache
247 _drupal_flush_css_js();
248 }
249
250 /**
251 * Get the content of a stylesheet from the database
252 *
253 * @param $sheet The encoded name of a stylesheet
254 * @param $vid The version id to load, optional. If omitted, will load latest. (redundant?)
255 */
256 function cssapi_load_sheet($sheet, $vid = 0) {
257 if ($vid) {
258 $return = db_result(db_query("SELECT content FROM {cssapi} WHERE sheet = '%s' AND vid = %d"), $sheet, $vid);
259 }
260 else {
261 $return = db_result(db_query("SELECT content FROM {cssapi} WHERE sheet = '%s' ORDER BY timestamp DESC"), $sheet);
262 }
263 return $return;
264 }
265
266 function cssapi_load_sheet_revision($vid) {
267 return db_fetch_object(db_query('SELECT content, sheet, timestamp FROM {cssapi} WHERE vid = %d', $vid));
268 }
269
270 /**
271 * Given a non-editable CSS file, return the path to the editable CSS file
272 *
273 * Path scheme:
274 * {files_dir}/{variable_get('cssapi_dir', 'dcss')}/{md5(theme_name.path_to_file)}
275 *
276 * Path examples:
277 * files/dgnr/garland/modules/system/system.css
278 * files/dgnr/pushbutton/themes/pushbutton/style.css
279 * sites/default/files/dgnr/zen_classic/sites/all/modules/fivestar/widgets/flames/flames.css
280 *
281 * @param $path
282 * path to the non-editable CSS file
283 * @param $theme
284 * the name of the theme. this is prefixed in the md5 value to avoid conflicts
285 * between different themes overriding the same files.
286 * if you'd like to have further granularity with perhaps multiple "styles"
287 * per theme, you could append another key to this value - something like "zen/plain"
288 * @param $check_exists
289 * if set to TRUE, the function will check to see if the file exists and return
290 * FALSE if not found
291 *
292 * @return
293 * The path to the editable CSS file. If $check_exists is TRUE, the function
294 * will return boolean FALSE if the file doesn't exist (the path if it does).
295 */
296 function cssapi_get_editable_path($path, $theme, $check_exists = FALSE) {
297 // hmmm... it sure would be nice if we kept these files named the same as the original
298 $filename = md5($theme .'/'. $path) .'.css';
299 $path = file_directory_path() .'/'. variable_get('cssapi_dir', 'dcss') .'/'. $filename;
300 if ($check_exists && !file_exists($path)) {
301 $path = FALSE;
302 }
303 return $path;
304 }
305
306 /**
307 * Get just the name of a CSS file from a path
308 */
309 function cssapi_get_short_name($path) {
310 // @TODO change this to use basename()
311 preg_match('/([^\/]*?\.css)/i', $path, $matches);
312 return $matches[0];
313 }
314
315 // *********************************************
316 // RULE EDITING FUNCTIONS ******************** (incomplete)
317 // *********************************************
318
319 /**
320 * API-type function to return the entire CSS declaration
321 *
322 * @param $sheet Complete path to the style sheet.
323 * @param $rule The selectors associated with this declaration.
324 * @return the entire matches array from preg_match()
325 */
326 function cssapi_get_rule($sheet, $rule) {
327 $sheet = _cssapi_get_path($sheet);
328 // load the contents of the style sheet
329 $contents = drupal_load_stylesheet($sheet, FALSE);
330
331 // find this rule declaration within the stylesheet content
332 // create the regex
333 // replace "," with ",\s*" and stick this into a larger regex
334 $regex = '/\s*'. preg_replace('/,[\s$]*/s', ',[\s$]*', preg_quote($rule, '/')) .'[\s$]*?\{[\s$]*?(\w[\w\W$]*?)[\s$]*?\}/';
335 // run the regex and store results in $match
336 preg_match($regex, $contents, $matches);
337 return $matches;
338 }
339
340 function _cssapi_get_path($sheet) {
341 // some JS/Ajax scripts may send the whole CSS URL, so we convert this to a Drupal path
342 if (strpos($sheet, 'http:') === 0 || strpos($sheet, 'https:') === 0) {
343 // Sheet is a full URL. Convert this to a Drupal path.
344 $parsed = parse_url($sheet);
345 $regex = '/'. preg_quote(base_path(), '/') .'/';
346 $sheet = preg_replace($regex, '', $parsed['path'], 1);
347 }
348 return $sheet;
349 }

  ViewVC Help
Powered by ViewVC 1.1.2