|
1 <?php |
|
2 |
|
3 /** |
|
4 * @file |
|
5 * Implements HTML Purifier as a Drupal filter. |
|
6 */ |
|
7 |
|
8 |
|
9 |
|
10 // -- HOOK IMPLEMENTATIONS -------------------------------------------------- // |
|
11 |
|
12 /** |
|
13 * Implements hook_flush_caches(). |
|
14 */ |
|
15 function htmlpurifier_flush_caches() { |
|
16 return array('cache_htmlpurifier'); |
|
17 } |
|
18 |
|
19 /** |
|
20 * Implements hook_help(). |
|
21 */ |
|
22 function htmlpurifier_help($path, $arg) { |
|
23 $output = NULL; |
|
24 switch ($path) { |
|
25 case 'admin/help#htmlpurifier': |
|
26 $output = t(<<<TEXT |
|
27 The HTML Purifier Drupal module provides a text filter that removes |
|
28 malicious HTML and ensures standards compliant output. You can modify |
|
29 text formats at <a href="@formats">the format configurations page</a>. |
|
30 TEXT |
|
31 , array('@formats' => url('admin/config/content/formats'))); |
|
32 break; |
|
33 } |
|
34 return $output; |
|
35 } |
|
36 |
|
37 /* |
|
38 * Implements hook_menu(). |
|
39 */ |
|
40 function htmlpurifier_menu() { |
|
41 $items['admin/config/content/htmlpurifier'] = array( |
|
42 'title' => 'HTML Purifier settings', |
|
43 'description' => 'Configure overall settings for the HTML Purifier filters, including how they are cached.', |
|
44 'page callback' => 'drupal_get_form', |
|
45 'page arguments' => array('htmlpurifier_admin_settings'), |
|
46 'access arguments' => array('administer filters'), |
|
47 'file' => 'htmlpurifier.admin.inc', |
|
48 ); |
|
49 |
|
50 return $items; |
|
51 } |
|
52 |
|
53 /** |
|
54 * Implements hook_cron(). |
|
55 */ |
|
56 function htmlpurifier_cron() { |
|
57 // Force an attempt at checking for a new version; this is safe to do in |
|
58 // hook_cron because a slow timeout will not degrade the user experience. |
|
59 htmlpurifier_check_version(TRUE); |
|
60 } |
|
61 |
|
62 /** |
|
63 * Checks for updates to the HTML Purifier library. |
|
64 */ |
|
65 function htmlpurifier_check_version($force = FALSE) { |
|
66 if ($force || !variable_get('htmlpurifier_version_check_failed', FALSE)) { |
|
67 // Maybe this should be changed in the future: |
|
68 $result = drupal_http_request('http://htmlpurifier.org/live/VERSION'); |
|
69 if ($result->code == 200) { |
|
70 $version = trim($result->data); |
|
71 if (variable_get('html_purifier_version_check_failed', FALSE) == TRUE) { |
|
72 variable_set('htmlpurifier_version_check_failed', FALSE); |
|
73 } |
|
74 $current_version = variable_get('htmlpurifier_version_current', ''); |
|
75 if ($current_version != $version) { |
|
76 variable_set('htmlpurifier_version_current', $version); |
|
77 } |
|
78 return $version; |
|
79 } |
|
80 else { |
|
81 variable_set('htmlpurifier_version_check_failed', TRUE); |
|
82 // Delete any previously known "latest" version so that people can be |
|
83 // alerted if a problem appears on a previously working site. |
|
84 variable_del('htmlpurifier_version_current'); |
|
85 } |
|
86 } |
|
87 } |
|
88 |
|
89 /** |
|
90 * Implements hook_filter_info(). |
|
91 */ |
|
92 function htmlpurifier_filter_info() { |
|
93 _htmlpurifier_load(); |
|
94 $filters['htmlpurifier_basic'] = array( |
|
95 'title' => t('HTML Purifier'), |
|
96 'description' => t('Removes malicious HTML code and ensures that the ' . |
|
97 'output is standards compliant. <strong>Warning:</strong> For ' . |
|
98 'performance reasons, please ensure that there are no highly dynamic ' . |
|
99 'filters before HTML Purifier. '), |
|
100 'process callback' => '_htmlpurifier_process', |
|
101 'settings callback' => '_htmlpurifier_settings', |
|
102 'default settings' => array( |
|
103 'htmlpurifier_help' => TRUE, |
|
104 ), |
|
105 'tips callback' => '_htmlpurifier_filter_tips', |
|
106 ); |
|
107 $filters['htmlpurifier_advanced'] = array( |
|
108 'title' => t('HTML Purifier (advanced)'), |
|
109 'description' => $filters['htmlpurifier_basic']['description'] . t('<em>This version has advanced configuration options, do not enable both at the same time.</em>'), |
|
110 ) + $filters['htmlpurifier_basic']; |
|
111 return $filters; |
|
112 } |
|
113 |
|
114 /** |
|
115 * Implements of hook_nodeapi(). |
|
116 */ |
|
117 function htmlpurifier_nodeapi(&$node, $op, $a3, $a4) { |
|
118 if ($op == 'view') { |
|
119 |
|
120 // Should we load CSS cache data from teaser or body? |
|
121 if ($a3 == TRUE) { |
|
122 _htmlpurifier_add_css( $node->content['teaser']['#value'], $node->nid ); |
|
123 } |
|
124 else { |
|
125 _htmlpurifier_add_css( $node->content['body']['#value'], $node->nid ); |
|
126 } |
|
127 } |
|
128 // @todo: Deal with CCK fields - probably needs to go in op alter? |
|
129 } |
|
130 |
|
131 // -- INTERNAL FUNCTIONS ---------------------------------------------------- // |
|
132 |
|
133 /** |
|
134 * Filter tips callback, used by htmlpurifier_filter_info(). |
|
135 */ |
|
136 function _htmlpurifier_filter_tips($delta, $format, $long = FALSE) { |
|
137 if (!empty($delta->settings['htmlpurifier_help'])) { |
|
138 return t('HTML tags will be transformed to conform to HTML standards.'); |
|
139 } |
|
140 } |
|
141 |
|
142 /** |
|
143 * Process callback, used by htmlpurifier_filter_info(). |
|
144 * |
|
145 * Passes data along to the helper function with instructions to always try to |
|
146 * use this module's custom cache mechanism. |
|
147 * |
|
148 * We need this helper function because the filter system passes in $cache as |
|
149 * fifth parameter to this hook (which corresponds to whether or not the core |
|
150 * filter system itself will cache the data), but we want to cache it always so |
|
151 * we need to ignore that parameter. |
|
152 */ |
|
153 function _htmlpurifier_process($text, $filter, $format, $langcode, $cache) { |
|
154 return _htmlpurifier_process_text($text, $filter, $format, $langcode, TRUE); |
|
155 } |
|
156 |
|
157 /** |
|
158 * Helper function for hook_nodeapi |
|
159 * Finds extracted style blocks based on a cache link left by hook_filter |
|
160 * Aggregates the extracted style blocks and adds them to the document head |
|
161 * Also removes the cache link left in hook_filter to the CSS cache |
|
162 * |
|
163 * @param string &$field |
|
164 * Field to process, this should be the actual field value |
|
165 * ex. $node->content['body']['#value'] |
|
166 * |
|
167 * @param int $nid |
|
168 * Node ID of the node to which these stylesheets belong |
|
169 * Since filters don't know their node context, we have to use a token |
|
170 * to generate the stylesheet scope, and replace it in hook_nodeapi |
|
171 */ |
|
172 function _htmlpurifier_add_css( &$field, $nid ) { |
|
173 |
|
174 // Some basic validation to assure we really got a rendered field |
|
175 if (!is_string($field)) { |
|
176 return; |
|
177 } |
|
178 |
|
179 $cache_matches = array(); |
|
180 $cache_match = preg_match('#<!-- HTML Purifier Cache \#([-\w]*:[\w]*) -->#', $field, $cache_matches); |
|
181 |
|
182 // If there's an HTML Purifier Cache #, we need to load CSSTidy blocks |
|
183 if ($cache_match == 1) { |
|
184 $cid = 'css:' . $cache_matches[1]; |
|
185 $old = cache_get($cid, 'cache_htmlpurifier'); |
|
186 |
|
187 // We should always have some cached style blocks to load, but if we don't, just bail |
|
188 if ($old) { |
|
189 $styles = array(); |
|
190 $style_rendered = ''; |
|
191 foreach ($old->data as $i => $style) { |
|
192 |
|
193 // Replace Node ID tokens if necessary, otherwise use cached CSSTidy blocks |
|
194 // NOTE: This token is forgeable, but we expect that if the user |
|
195 // is able to invoke this transformation, it will be relatively |
|
196 // harmless. |
|
197 if (strpos($style, '[%HTMLPURIFIER:NID%]') !== FALSE) { |
|
198 $styles[$i] = str_replace('[%HTMLPURIFIER:NID%]', (int) $nid, $style); |
|
199 } |
|
200 else { |
|
201 $styles[$i] = $style; |
|
202 } |
|
203 |
|
204 // Save any CSSTidy blocks we find to be rendered in the document head |
|
205 if (!empty($style)) { |
|
206 $style_rendered .= $styles[$i] . "\n"; |
|
207 } |
|
208 } |
|
209 |
|
210 // Add the rendered stylesheet to the document header |
|
211 if ($style_rendered != '') { |
|
212 drupal_set_html_head('<style type="text/css">' . "\n" . '<!--' . "\n" . $style_rendered . '--></style>'); |
|
213 } |
|
214 |
|
215 // Remove the HTML Purifier cache key from the field argument |
|
216 $field = str_replace($cache_matches[0], '', $field); |
|
217 |
|
218 // If we had to update CSSTidy blocks, cache the results |
|
219 if ($old->data != $styles) { |
|
220 cache_set($cid, $styles, 'cache_htmlpurifier', CACHE_PERMANENT); |
|
221 } |
|
222 } |
|
223 } |
|
224 } |
|
225 |
|
226 |
|
227 |
|
228 /** |
|
229 * Processes HTML according to a format and returns purified HTML. Makes a |
|
230 * cache pass if possible. |
|
231 * |
|
232 * @param string $text |
|
233 * Text to purify |
|
234 * @param object $filter |
|
235 * The filter object containing settings for the given format. |
|
236 * @param object $format |
|
237 * The format object of the text to be filtered. |
|
238 * @param string $langcode |
|
239 * The language code of the text to be filtered. |
|
240 * @param boolean $cache |
|
241 * Whether or not to check the cache. |
|
242 * |
|
243 * @note |
|
244 * We ignore $delta because the only difference it makes is in the configuration |
|
245 * screen. |
|
246 */ |
|
247 function _htmlpurifier_process_text($text, $filter, $format, $langcode, $cache = TRUE) { |
|
248 // No need to run the filter if there isn't anything to filter |
|
249 // See https://drupal.org/node/1821178 |
|
250 if ($text === '') { |
|
251 return; |
|
252 } |
|
253 |
|
254 if ($cache) { |
|
255 $cid = $format->format . ':' . $langcode . ':' . hash('sha256', $text); |
|
256 $old = cache_get($cid, 'cache_htmlpurifier'); |
|
257 if ($old) return $old->data; |
|
258 } |
|
259 |
|
260 _htmlpurifier_load(); |
|
261 $config = _htmlpurifier_get_config($format->format); |
|
262 |
|
263 // If ExtractStyleBlocks is enabled, we'll need to do a bit more for CSSTidy |
|
264 $config_extractstyleblocks = $config->get('Filter.ExtractStyleBlocks'); |
|
265 |
|
266 // Maybe this works if CSSTidy is at root? CSSTidy could be other places though |
|
267 if ($config_extractstyleblocks == TRUE) { |
|
268 _htmlpurifier_load_csstidy(); |
|
269 } |
|
270 |
|
271 $purifier = new HTMLPurifier($config); |
|
272 $ret = $purifier->purify($text); |
|
273 |
|
274 // If using Filter.ExtractStyleBlocks we need to handle the CSSTidy output |
|
275 if ($config_extractstyleblocks == TRUE) { |
|
276 |
|
277 // We're only going to bother if we're caching! - no caching? no style blocks! |
|
278 if ($cache) { |
|
279 |
|
280 // Get style blocks, cache them, and help hook_nodeapi find the cache |
|
281 $styles = $purifier->context->get('StyleBlocks'); |
|
282 cache_set('css:' . $cid, $styles, 'cache_htmlpurifier', CACHE_PERMANENT); |
|
283 $ret = '<!-- HTML Purifier Cache #' . $cid . ' -->' . $ret; |
|
284 } |
|
285 } |
|
286 |
|
287 if ($cache) cache_set($cid, $ret, 'cache_htmlpurifier', CACHE_PERMANENT); |
|
288 |
|
289 return $ret; |
|
290 } |
|
291 |
|
292 /** |
|
293 * Loads the HTML Purifier library, and performs global initialization. |
|
294 */ |
|
295 function _htmlpurifier_load() { |
|
296 static $done = FALSE; |
|
297 if ($done) { |
|
298 return; |
|
299 } |
|
300 $done = TRUE; |
|
301 $module_path = drupal_get_path('module', 'htmlpurifier'); |
|
302 $library_path = $module_path; |
|
303 if (function_exists('libraries_get_path')) { |
|
304 $library_path = libraries_get_path('htmlpurifier'); |
|
305 // This may happen if the user has HTML Purifier installed under the |
|
306 // old configuration, but also installed libraries and forgot to |
|
307 // move it over. There is code for emitting errors in |
|
308 // htmlpurifier.install when this is the case. |
|
309 if (!file_exists("$library_path/library/HTMLPurifier.auto.php")) { |
|
310 // Check for an alternate phrasing and error about it |
|
311 if (file_exists("$library_path/HTMLPurifier.auto.php") && |
|
312 !file_exists("$module_path/library/HTMLPurifier.auto.php")) { |
|
313 echo "HTML Purifier was installed improperly; move contents of folder $library_path to $library_path/library"; |
|
314 exit; |
|
315 } |
|
316 $library_path = $module_path; |
|
317 } |
|
318 } |
|
319 |
|
320 require_once "$library_path/library/HTMLPurifier.auto.php"; |
|
321 require_once "$module_path/HTMLPurifier_DefinitionCache_Drupal.php"; |
|
322 |
|
323 $factory = HTMLPurifier_DefinitionCacheFactory::instance(); |
|
324 $factory->register('Drupal', 'HTMLPurifier_DefinitionCache_Drupal'); |
|
325 |
|
326 // Register the version as a variable: |
|
327 $current_version = variable_get('htmlpurifier_version_ours', FALSE); |
|
328 if ($current_version != HTMLPurifier::VERSION) { |
|
329 variable_set('htmlpurifier_version_ours', HTMLPurifier::VERSION); |
|
330 } |
|
331 } |
|
332 |
|
333 /** |
|
334 * Returns the HTMLPurifier_Config object corresponding to a text format. |
|
335 * @param int $format |
|
336 * (Optional) Text format ID. If left empty, the default configuration is |
|
337 * returned. |
|
338 * @return |
|
339 * Instance of HTMLPurifier_Config. |
|
340 */ |
|
341 function _htmlpurifier_get_config($format = 0) { |
|
342 |
|
343 $config = HTMLPurifier_Config::createDefault(); |
|
344 |
|
345 $config->set('AutoFormat.AutoParagraph', TRUE); |
|
346 $config->set('AutoFormat.Linkify', TRUE); |
|
347 $config->set('HTML.Doctype', 'XHTML 1.0 Transitional'); // Probably |
|
348 $config->set('Core.AggressivelyFixLt', TRUE); |
|
349 $config->set('Cache.DefinitionImpl', 'Drupal'); |
|
350 |
|
351 if (!empty($_SERVER['SERVER_NAME'])) { |
|
352 // SERVER_NAME is more reliable than HTTP_HOST |
|
353 $config->set('URI.Host', $_SERVER['SERVER_NAME']); |
|
354 } |
|
355 |
|
356 if (defined('LANGUAGE_RTL') && $GLOBALS['language']->direction === LANGUAGE_RTL) { |
|
357 $config->set('Attr.DefaultTextDir', 'rtl'); |
|
358 } |
|
359 |
|
360 if ($format && ($config_function = _htmlpurifier_config_load($format))) { |
|
361 $config_function($config); |
|
362 } |
|
363 else { |
|
364 // We only support one instance of this module's filters (either basic or |
|
365 // advanced) per text format, so choose the first settings we find. |
|
366 // TODO: This is awkward, but the most straightforward conversion from the |
|
367 // D6 version, which also treated this as a per-format setting and |
|
368 // therefore had the same limitation. |
|
369 $filters = $format ? filter_list_format($format) : array(); |
|
370 if (!empty($filters['htmlpurifier_advanced']->status) && isset($filters['htmlpurifier_advanced']->settings['htmlpurifier_advanced_config'])) { |
|
371 $config_data = $filters['htmlpurifier_advanced']->settings['htmlpurifier_advanced_config']; |
|
372 } |
|
373 elseif (!empty($filters['htmlpurifier_basic']->status) && isset($filters['htmlpurifier_basic']->settings['htmlpurifier_basic_config'])) { |
|
374 $config_data = $filters['htmlpurifier_basic']->settings['htmlpurifier_basic_config']; |
|
375 } |
|
376 else { |
|
377 $config_data = FALSE; |
|
378 } |
|
379 |
|
380 if (!empty($config_data['Filter.ExtractStyleBlocks'])) { |
|
381 if (!_htmlpurifier_load_csstidy()) { |
|
382 $config_data['Filter.ExtractStyleBlocks'] = '0'; |
|
383 drupal_set_message(t("Could not enable ExtractStyleBlocks because CSSTidy was not installed. You can download CSSTidy module from <a href='http://drupal.org/project/csstidy'>http://drupal.org/project/csstidy</a>"), 'error', FALSE); |
|
384 } |
|
385 } |
|
386 // {FALSE, TRUE, FALSE} = {no index, everything is allowed, don't do mq fix} |
|
387 $config->mergeArrayFromForm($config_data, FALSE, TRUE, FALSE); |
|
388 } |
|
389 |
|
390 return $config; |
|
391 |
|
392 } |
|
393 |
|
394 function _htmlpurifier_load_csstidY() { |
|
395 // If CSSTidy module is installed, it should have a copy we can use |
|
396 $csstidy_path = drupal_get_path('module', 'csstidy') . '/csstidy'; |
|
397 |
|
398 // Some future-proofing for library path |
|
399 if (function_exists('libraries_get_path')) { |
|
400 $csstidy_library = libraries_get_path('csstidy'); |
|
401 if (file_exists("$csstidy_library/class.csstidy.php")) { |
|
402 $csstidy_path = $csstidy_library; |
|
403 } |
|
404 } |
|
405 |
|
406 // Load CSSTidy if we can find it |
|
407 if (file_exists("$csstidy_path/class.csstidy.php")) { |
|
408 require_once "$csstidy_path/class.csstidy.php"; |
|
409 return TRUE; |
|
410 } |
|
411 return FALSE; |
|
412 } |
|
413 |
|
414 /** |
|
415 * Returns the name of the configuration function for $format, or FALSE if none |
|
416 * exists. Function name will be htmlpurifier_config_N. |
|
417 * |
|
418 * @param int $format |
|
419 * Integer format to check function for. |
|
420 * @return |
|
421 * String function name for format, or FALSE if none. |
|
422 */ |
|
423 function _htmlpurifier_config_load($format) { |
|
424 $config_file = drupal_get_path('module', 'htmlpurifier') . "/config/$format.php"; |
|
425 $config_function = "htmlpurifier_config_$format"; |
|
426 if ( |
|
427 !function_exists($config_function) && |
|
428 file_exists($config_file) |
|
429 ) { |
|
430 include_once $config_file; |
|
431 } |
|
432 return function_exists($config_function) ? $config_function : FALSE; |
|
433 } |
|
434 |
|
435 /** |
|
436 * Generates a settings form for configuring HTML Purifier. |
|
437 * |
|
438 * @param array $form |
|
439 * The prepopulated form array. |
|
440 * @param array $form_state |
|
441 * The form state of the (entire) configuration form. |
|
442 * @param object $filter |
|
443 * The filter object containing settings for the given format. $filter->name |
|
444 * can be either 'htmlpurifier_basic' or 'htmlpurifier_advanced' (the two |
|
445 * filters defined by this module). |
|
446 * @param object $format |
|
447 * The format object being configured. |
|
448 * @param array $defaults |
|
449 * The default settings for the filter, as defined in 'default settings' in |
|
450 * hook_filter_info(). |
|
451 * |
|
452 * @return |
|
453 * Form API array. |
|
454 */ |
|
455 function _htmlpurifier_settings($form, &$form_state, $filter, $format, $defaults) { |
|
456 _htmlpurifier_load(); |
|
457 |
|
458 // Dry run, testing for errors: |
|
459 _htmlpurifier_process_text('', $filter, $format, LANGUAGE_NONE, FALSE); |
|
460 |
|
461 $module_path = drupal_get_path('module', 'htmlpurifier'); |
|
462 |
|
463 $settings = array(); |
|
464 |
|
465 $settings['#attached']['css'][] = "$module_path/config-form.css"; |
|
466 $settings['#attached']['js'][] = "$module_path/config-form.js"; |
|
467 $settings['#attached']['js'][] = array( |
|
468 'data' => HTMLPurifier_Printer_ConfigForm::getJavaScript(), |
|
469 'type' => 'inline', |
|
470 ); |
|
471 |
|
472 $settings['htmlpurifier_help'] = array( |
|
473 '#type' => 'checkbox', |
|
474 '#title' => t('Display help text'), |
|
475 '#default_value' => isset($filter->settings['htmlpurifier_help']) ? $filter->settings['htmlpurifier_help'] : $defaults['htmlpurifier_help'], |
|
476 '#description' => t('If enabled, a short note will be added to the filter tips explaining that HTML will be transformed to conform with HTML standards. You may want to disable this option when the HTML Purifier is used to check the output of another filter like BBCode.'), |
|
477 ); |
|
478 if ($config_function = _htmlpurifier_config_load($format->format)) { |
|
479 $settings['notice'] = array( |
|
480 '#type' => 'markup', |
|
481 '#value' => t('<div>Configuration function <code>!function()</code> is already defined. To edit HTML Purifier\'s configuration, edit the corresponding configuration file, which is usually <code>htmlpurifier/config/!format.php</code>. To restore the web configuration form, delete or rename this file.</div>', |
|
482 array('!function' => $config_function, '!format' => $format->format)), |
|
483 ); |
|
484 } |
|
485 else { |
|
486 if ($filter->name == 'htmlpurifier_basic') { |
|
487 $title = t('Configure HTML Purifier'); |
|
488 $allowed = array( |
|
489 'URI.DisableExternalResources', |
|
490 'URI.DisableResources', |
|
491 'URI.Munge', |
|
492 'Attr.EnableID', |
|
493 'HTML.Allowed', |
|
494 'HTML.ForbiddenElements', |
|
495 'HTML.ForbiddenAttributes', |
|
496 'HTML.SafeObject', |
|
497 'Output.FlashCompat', |
|
498 'AutoFormat.RemoveEmpty', |
|
499 'AutoFormat.Linkify', |
|
500 'AutoFormat.AutoParagraph', |
|
501 ); |
|
502 } |
|
503 else { |
|
504 $title = t('Advanced configuration options'); |
|
505 $allowed = TRUE; |
|
506 } |
|
507 |
|
508 $intro = |
|
509 '<div class="form-item"><h3>' . |
|
510 $title . |
|
511 '</h3><div class="description">' . |
|
512 t('Please click on a directive name for more information on what it does before enabling or changing anything! Changes will not apply to old entries until you clear the cache (see the <a href="@url">settings page</a>).', array('@url' => url('admin/config/content/htmlpurifier'))) . |
|
513 '</div></div>'; |
|
514 |
|
515 $config = _htmlpurifier_get_config($format->format); |
|
516 $config_form = new HTMLPurifier_Printer_ConfigForm( |
|
517 $filter->name . '_config', 'http://htmlpurifier.org/live/configdoc/plain.html#%s' |
|
518 ); |
|
519 $settings[$filter->name . '_config'] = array( |
|
520 '#markup' => $intro . $config_form->render($config, $allowed, FALSE), |
|
521 '#after_build' => array('_htmlpurifier_config_hack'), |
|
522 ); |
|
523 } |
|
524 |
|
525 return $settings; |
|
526 } |
|
527 |
|
528 /** |
|
529 * Fills out the form state with extra post data originating from the |
|
530 * HTML Purifier configuration form. This is an #after_build hook function. |
|
531 * |
|
532 * @warning |
|
533 * If someone ever gets the smart idea of changing the parameters to |
|
534 * this function, I'm SOL! ;-) |
|
535 * Also, this function does not work correctly if both filters from this |
|
536 * module are enabled for the same format, since only one set of submitted |
|
537 * values will make it through. |
|
538 */ |
|
539 function _htmlpurifier_config_hack($form_element, &$form_state) { |
|
540 $parents = $form_element['#parents']; |
|
541 $key = end($parents); |
|
542 if (isset($form_state['input'][$key])) { |
|
543 $value = $form_state['input'][$key]; |
|
544 foreach (array_reverse($parents) as $parent) { |
|
545 $value = array($parent => $value); |
|
546 } |
|
547 $form_state['values'] = array_merge_recursive($form_state['values'], $value); |
|
548 } |
|
549 foreach ($form_state['values'] as $i => $config_data) { |
|
550 if (!is_array($config_data)) continue; |
|
551 if (!empty($config_data['Filter.ExtractStyleBlocks'])) { |
|
552 if (!empty($config_data['Null_Filter.ExtractStyleBlocks.Scope'])) { |
|
553 drupal_set_message(t("You have not set <code>Filter.ExtractStyleBlocks.Scope</code>; this means that users can add CSS that affects all of your Drupal theme and not just their content block. It is recommended to set this to <code>#node-[%HTMLPURIFIER:NID%]</code> (including brackets) which will automatically ensure that CSS directives only apply to their node."), 'warning', FALSE); |
|
554 } |
|
555 elseif (!isset($config_data['Filter.ExtractStyleBlocks.Scope']) || $config_data['Filter.ExtractStyleBlocks.Scope'] !== '#node-[%HTMLPURIFIER:NID%]') { |
|
556 drupal_set_message(t("You have enabled Filter.ExtractStyleBlocks.Scope, but you did not set it to <code>#node-[%HTMLPURIFIER:NID%]</code>; CSS may not work unless you have special theme support."), 'warning', FALSE); |
|
557 } |
|
558 } |
|
559 } |
|
560 return $form_element; |
|
561 } |
|
562 |
|
563 /** |
|
564 * Clears the HTML Purifier internal Drupal cache. |
|
565 */ |
|
566 function _htmlpurifier_clear_cache($form, &$form_state) { |
|
567 drupal_set_message(t('Cache cleared.')); |
|
568 cache_clear_all('*', 'cache_htmlpurifier', TRUE); |
|
569 cache_clear_all('htmlpurifier:', 'cache', TRUE); |
|
570 } |
|
571 |
|
572 // vim: syntax=php |