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

Contents of /contributions/modules/css/css.module

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


Revision 1.4 - (show annotations) (download) (as text)
Fri Dec 26 15:20:36 2008 UTC (11 months ago) by fax8
Branch: MAIN
CVS Tags: HEAD
Branch point for: DRUPAL-6--1
Changes since 1.3: +79 -33 lines
File MIME type: text/x-php
#347481 by jchan: Porting css.module to Drupal 6.x
1 <?php
2 // $Id: $
3
4 /**
5 * @file
6 * Adds the support for css on node creation.
7 * We add the ability for each node to have an attached css
8 *
9 * @author Fabio Varesano <fvaresano at yahoo dot it>
10 * @updated to Drupal 5 by Christopher Skauss <christopher skauss at gmail dot com>
11 * @modified drupal 5 Version by Whispero
12 * @updated for Drupal 6 by Joshua Chan <josh at joshuachan dot ca>
13 *
14 * To store this extra information, we need an auxiliary database table.
15 *
16 * Database definition:
17 * @code
18 CREATE TABLE css (
19 nid int(10) unsigned NOT NULL default '0',
20 css text NULL default NULL,
21 PRIMARY KEY (nid)
22 )
23 * @endcode
24 */
25
26 /**
27 * Implementation of hook_help().
28 */
29 function css_help($section) {
30 switch ($section) {
31 case 'admin/modules#description':
32 // This description is shown in the listing at admin/modules.
33 return t('A module which add customizable CSS support.');
34 }
35 }
36
37 /**
38 * Implementation of hook_menu()
39 */
40 function css_menu() {
41 $items = array();
42 // defines the callback for getting the css file. we use
43 // css/get as path instead of only css to avoid that in some
44 // installs users have yet a directory called css
45 $items['css/get'] = array(
46 'title' => 'css',
47 'path' => 'css/get',
48 'page callback' => 'css_get',
49 'access arguments' => array('access content'),
50 'type' => MENU_CALLBACK,
51 );
52 return $items;
53 }
54
55 /**
56 * Implementation of hook_perm()
57 */
58 function css_perm() {
59 return array('create css for nodes');
60 }
61
62 /**
63 * Implemenation of hook_form_alter()
64 */
65 function css_form_alter(&$form, $form_state, $form_id) {
66 //Add a text area to the form where users will put their csses rules.
67 if (user_access('create css for nodes') && variable_get('css__'.$form['#node']->type, FALSE)) {
68 if (isset($form['type']) && $form['type']['#value'] .'_node_form' == $form_id) {
69 $node = $form['#node'];
70 // _form_form code follows:
71 $form['css_css'] = array(
72 '#type' => 'textarea',
73 '#title' => t('CSS'),
74 '#default_value' => $node->css_css,
75 '#cols' => 60,
76 '#rows' => 10,
77 '#description' => t('Insert here the css rules for this node. You can use css defined for other nodes using <em>@import "?q=css/get/x";</em> where x is the identification number of the node which contains the css you want to use.'),
78 '#attributes' => NULL,
79 '#required' => FALSE,
80 );
81 }
82 }
83 // Create a settings on content types configuration page
84 // which enable to activate/deactivate css editing for a node type
85 if (isset($form['#node_type']) && 'node_type_form' == $form_id) {
86 $form['workflow']['css_'.$node->type] = array(
87 '#type' => 'checkbox',
88 '#title' => t('Enable CSS Editing.'),
89 '#return_value' => 1,
90 '#default_value' => variable_get('css__'.$form['#node_type']->type, FALSE),
91 );
92 }
93 }
94
95 /**
96 * Implementation of hook_nodeapi().
97 */
98 function css_nodeapi(&$node, $op, $teaser = NULL, $page = NULL) {
99 static $prev_op = NULL;
100
101 if (variable_get('css__'. $node->type, FALSE)) { // check that CSS editing is enabled for the given node type
102 switch ($op) {
103
104 // Controls for valid input data
105 case 'validate':
106 // Check for potentially malicious tags
107 $pattern = '~<\s*\/?\s*(style|script|meta)\s*.*?>~i';
108 if (preg_match($pattern, $node->css_css)) {
109 form_set_error('css_css', t('Please do not include any tags.'));
110 }
111 break;
112
113 // Now that the form has been properly completed, it is time to commit the new
114 // data to the database.
115 case 'insert':
116 if (!empty($node->css_css)) {
117 db_query("INSERT INTO {css} (nid, css) VALUES (%d, '%s')", $node->nid, $node->css_css);
118 }
119 break;
120
121 // If the form was called to edit an existing node rather than create a new
122 // one, this operation gets called instead. We use a DELETE then INSERT rather
123 // than an UPDATE just in case the rating didn't exist for some reason.
124 case 'update':
125 db_query("DELETE FROM {css} WHERE nid = %d", $node->nid);
126 if (!empty($node->css_css)) {
127 db_query("INSERT INTO {css} (nid, css) VALUES (%d, '%s')", $node->nid, $node->css_css);
128 }
129 break;
130
131 // If the node is being deleted, we need this opportunity to clean up after
132 // ourselves.
133 case 'delete':
134 db_query('DELETE FROM {css} WHERE nid = %d', $node->nid);
135 break;
136
137 // Now we need to take care of loading one of the extended nodes from the
138 // database. An array containing our extra field needs to be returned.
139 case 'load':
140 $object = db_fetch_object(db_query('SELECT css FROM {css} WHERE nid = %d', $node->nid));
141 return array('css_css' => $object->css);
142 break;
143
144 // Using nodeapi('view') is more appropriate than using a filter here, because
145 // filters transform user-supplied content, whereas we are extending it with
146 // additional information.
147 case 'view':
148 if ($prev_op == 'validate') {
149 // 'validate' immediately followed by 'view' means this is a preview
150 if ($node->css_css) {
151 $css = '<style type="text/css" media="all"> '.
152 css_sanitize($node->css_css, 'preview').
153 ' </style>';
154 drupal_set_html_head($css, 'preview');
155 }
156 } else {
157 // Drupal 6 seems to check for the physical existence of CSS files
158 // before allowing them to be added. We have to include the virtual
159 // CSS file manually since it does not really exist.
160 if (!empty($node->css_css)) {
161 $link = url('css/get/'.$node->nid);
162 drupal_add_link(array(
163 'type' => 'text/css',
164 'rel' => 'stylesheet',
165 'media' => 'all',
166 'href' => $link,
167 ));
168 }
169 }
170 break;
171 }
172
173 $prev_op = $op; // used to determine Preview state
174 }
175 }
176
177 /**
178 * Return the css attached to the node.
179 * Last-Modified header is set to let browsers cache the css.
180 */
181 function css_get($nid = 0) {
182 if (is_numeric($nid) && $nid > 0) {
183 $object = db_fetch_object(db_query('SELECT css, changed FROM {css} c, {node} n WHERE n.nid = %d AND n.nid = c.nid', $nid));
184 if ($object) {
185 $date = gmdate('D, d M Y H:i:s', $object->changed) .' GMT';
186 header("Last-Modified: $date");
187 drupal_set_header('Content-Type: text/css; charset=utf-8');
188 print(css_sanitize($object->css));
189 }
190 }
191 }
192
193 /**
194 * Remove harmful code from CSS.
195 */
196 function css_sanitize($css, $type = 'view') {
197 switch ($type) {
198 case 'view':
199 // Are there any security vulnerabilites from external CSS files?
200 break;
201
202 case 'preview':
203 // Catch potentially malicious code
204 $patterns = array(
205 '~<\s*(/?)\s*(style|script|meta)\s*>~i',
206 );
207 $css = preg_replace($patterns, '<$1FILTERED $2>', $css);
208 break;
209
210 default:
211 $css = '';
212 break;
213 }
214
215 return $css;
216 }

  ViewVC Help
Powered by ViewVC 1.1.2