#1065976 by tekante and David_Rothstein: Reset plugin static cache during module...
[project/ctools.git] / ctools.module
CommitLineData
4f8d821f 1<?php
bfb163ad 2// $Id$
4f8d821f
EM
3
4/**
9398d6a6
EM
5 * @file
6 * CTools primary module file.
7 *
8 * Most of the CTools tools are in their own .inc files. This contains
9 * nothing more than a few convenience functions and some hooks that
10 * must be implemented in the module file.
11 */
5b52254b 12
a40482ac 13define('CTOOLS_API_VERSION', '2.0-alpha1');
821ab15c
EM
14
15/**
16 * Test the CTools API version.
17 *
18 * This function can always be used to safely test if CTools has the minimum
19 * API version that your module can use. It can also try to protect you from
20 * running if the CTools API version is too new, but if you do that you need
21 * to be very quick about watching CTools API releases and release new versions
22 * of your software as soon as the new release is made, or people might end up
23 * updating CTools and having your module shut down without any recourse.
24 *
25 * It is recommended that every hook of your module that might use CTools or
26 * might lead to a use of CTools be guarded like this:
27 *
28 * @code
29 * if (!module_invoke('ctools', 'api_version', '1.0')) {
30 * return;
31 * }
32 * @endcode
33 *
34 * Note that some hooks such as _menu() or _theme() must return an array().
35 *
36 * You can use it in your hook_requirements to report this error condition
37 * like this:
38 *
39 * @code
40 * define('MODULENAME_MINIMUM_CTOOLS_API_VERSION', '1.0');
41 * define('MODULENAME_MAXIMUM_CTOOLS_API_VERSION', '1.1');
42 *
43 * function MODULENAME_requirements($phase) {
44 * $requirements = array();
45 * if (!module_invoke('ctools', 'api_version', MODULENAME_MINIMUM_CTOOLS_API_VERSION, MODULENAME_MAXIMUM_CTOOLS_API_VERSION)) {
46 * $requirements['MODULENAME_ctools'] = array(
47 * 'title' => $t('MODULENAME required Chaos Tool Suite (CTools) API Version'),
48 * 'value' => t('Between @a and @b', array('@a' => MODULENAME_MINIMUM_CTOOLS_API_VERSION, '@b' => MODULENAME_MAXIMUM_CTOOLS_API_VERSION)),
49 * 'severity' => REQUIREMENT_ERROR,
50 * );
51 * }
52 * return $requirements;
53 * }
54 * @endcode
55 *
56 * Please note that the version is a string, not an floating point number.
57 * This will matter once CTools reaches version 1.10.
58 *
59 * A CTools API changes history will be kept in API.txt. Not every new
60 * version of CTools will necessarily update the API version.
61 * @param $minimum
62 * The minimum version of CTools necessary for your software to run with it.
63 * @param $maximum
64 * The maximum version of CTools allowed for your software to run with it.
65 */
66function ctools_api_version($minimum, $maximum = NULL) {
67 if (version_compare(CTOOLS_API_VERSION, $minimum, '<')) {
68 return FALSE;
69 }
70
71 if (isset($maximum) && version_compare(CTOOLS_API_VERSION, $maximum, '>')) {
72 return FALSE;
73 }
74
75 return TRUE;
76}
77
aeed3fef
SB
78// -----------------------------------------------------------------------
79// General utility functions
80
9398d6a6 81/**
dfd5d58a
SB
82 * Include .inc files as necessary.
83 *
84 * This fuction is helpful for including .inc files for your module. The
85 * general case is including ctools funcitonality like this:
86 *
87 * @code
88 * ctools_include('plugins');
89 * @endcode
90 *
91 * Similar funcitonality can be used for other modules by providing the $module
92 * and $dir arguments like this:
93 *
94 * @code
95 * // include mymodule/includes/import.inc
96 * ctools_include('import', 'mymodule');
97 * // include mymodule/plugins/foobar.inc
98 * ctools_include('foobar', 'mymodule', 'plugins');
99 * @endcode
100 *
101 * @param $file
102 * The base file name to be included.
103 * @param $module
104 * Optional module containing the include.
105 * @param $dir
106 * Optional subdirectory containing the include file.
4f8d821f 107 */
dfd5d58a 108function ctools_include($file, $module = 'ctools', $dir = 'includes') {
4f8d821f 109 static $used = array();
141aee3f
EM
110
111 $dir = '/' . ($dir ? $dir . '/' : '');
112
dfd5d58a 113 if (!isset($used[$module][$dir][$file])) {
141aee3f 114 require_once DRUPAL_ROOT . '/' . drupal_get_path('module', $module) . "$dir$file.inc";
aeed3fef 115 $used[$module][$dir][$file] = true;
4f8d821f 116 }
4f8d821f
EM
117}
118
119/**
aeed3fef
SB
120 * Provide the proper path to an image as necessary.
121 *
122 * This helper function is used by ctools but can also be used in other
123 * modules in the same way as explained in the comments of ctools_include.
124 *
125 * @param $image
126 * The base file name (with extension) of the image to be included.
127 * @param $module
128 * Optional module containing the include.
129 * @param $dir
130 * Optional subdirectory containing the include file.
71c6dfc1 131 */
aeed3fef
SB
132function ctools_image_path($image, $module = 'ctools', $dir = 'images') {
133 return drupal_get_path('module', $module) . "/$dir/" . $image;
71c6dfc1
EM
134}
135
136/**
aeed3fef
SB
137 * Include css files as necessary.
138 *
139 * This helper function is used by ctools but can also be used in other
140 * modules in the same way as explained in the comments of ctools_include.
141 *
142 * @param $file
143 * The base file name to be included.
144 * @param $module
145 * Optional module containing the include.
146 * @param $dir
147 * Optional subdirectory containing the include file.
4f8d821f 148 */
aeed3fef
SB
149function ctools_add_css($file, $module = 'ctools', $dir = 'css') {
150 drupal_add_css(drupal_get_path('module', $module) . "/$dir/$file.css");
4f8d821f 151}
25f97283
EM
152
153/**
aeed3fef
SB
154 * Include js files as necessary.
155 *
156 * This helper function is used by ctools but can also be used in other
157 * modules in the same way as explained in the comments of ctools_include.
158 *
159 * @param $file
160 * The base file name to be included.
161 * @param $module
162 * Optional module containing the include.
163 * @param $dir
164 * Optional subdirectory containing the include file.
9398d6a6 165 */
aeed3fef
SB
166function ctools_add_js($file, $module = 'ctools', $dir = 'js') {
167 drupal_add_js(drupal_get_path('module', $module) . "/$dir/$file.js");
be1a433c
EM
168}
169
170/**
a40482ac 171 * Format a javascript file name for use with $form['#attached']['js'].
dfd5d58a 172 *
a40482ac
SB
173 * This helper function is used by ctools but can also be used in other
174 * modules in the same way as explained in the comments of ctools_include.
175 *
176 * @code
177 * $form['#attached']['js'] = array(ctools_attach_js('auto-submit'));
178 * @endcode
dfd5d58a 179 *
a40482ac
SB
180 * @param $file
181 * The base file name to be included.
182 * @param $module
183 * Optional module containing the include.
184 * @param $dir
185 * Optional subdirectory containing the include file.
dfd5d58a 186 */
a40482ac
SB
187function ctools_attach_js($file, $module = 'ctools', $dir = 'js') {
188 return drupal_get_path('module', $module) . "/$dir/$file.js";
dfd5d58a
SB
189}
190
191/**
aeed3fef 192 * Get a list of roles in the system.
25f97283 193 *
aeed3fef
SB
194 * @return
195 * An array of role names keyed by role ID.
9398d6a6 196 */
aeed3fef
SB
197function ctools_get_roles() {
198 static $roles = NULL;
199 if (!isset($roles)) {
a40482ac
SB
200 $roles = user_roles(TRUE);
201 unset($roles[DRUPAL_AUTHENTICATED_RID]);
9398d6a6 202 }
aeed3fef
SB
203
204 return $roles;
9398d6a6
EM
205}
206
aeed3fef
SB
207/*
208 * Break x,y,z and x+y+z into an array. Numeric only.
209 *
210 * @param $str
211 * The string to parse.
212 *
213 * @return $object
214 * An object containing
215 * - operator: Either 'and' or 'or'
216 * - value: An array of numeric values.
0da7776f 217 */
aeed3fef
SB
218function ctools_break_phrase($str) {
219 $object = new stdClass();
220
221 if (preg_match('/^([0-9]+[+ ])+[0-9]+$/', $str)) {
222 // The '+' character in a query string may be parsed as ' '.
223 $object->operator = 'or';
224 $object->value = preg_split('/[+ ]/', $str);
225 }
226 else if (preg_match('/^([0-9]+,)*[0-9]+$/', $str)) {
227 $object->operator = 'and';
228 $object->value = explode(',', $str);
5e506485
EM
229 }
230
aeed3fef
SB
231 // Keep an 'error' value if invalid strings were given.
232 if (!empty($str) && (empty($object->value) || !is_array($object->value))) {
233 $object->value = array(-1);
234 $object->invalid_input = TRUE;
235 return $object;
5e506485
EM
236 }
237
aeed3fef
SB
238 if (empty($object->value)) {
239 $object->value = array();
5e506485
EM
240 }
241
aeed3fef
SB
242 // Doubly ensure that all values are numeric only.
243 foreach ($object->value as $id => $value) {
244 $object->value[$id] = intval($value);
245 }
246
247 return $object;
248}
249
250/**
251 * Set a token/value pair to be replaced later in the request, specifically in
252 * ctools_preprocess_page().
253 *
254 * @param $token
255 * The token to be replaced later, during page rendering. This should
256 * ideally be a string inside of an HTML comment, so that if there is
257 * no replacement, the token will not render on the page.
258 * @param $type
259 * The type of the token. Can be either 'variable', which will pull data
260 * directly from the page variables
261 * @param $argument
262 * If $type == 'variable' then argument should be the key to fetch from
263 * the $variables. If $type == 'callback' then it should either be the
264 * callback, or an array that will be sent to call_user_func_array().
265 *
266 * @return
267 * A array of token/variable names to be replaced.
268 */
269function ctools_set_page_token($token = NULL, $type = NULL, $argument = NULL) {
270 static $tokens = array();
271
272 if (isset($token)) {
273 $tokens[$token] = array($type, $argument);
5e506485 274 }
aeed3fef 275 return $tokens;
5e506485
EM
276}
277
aeed3fef
SB
278/**
279 * Easily set a token from the page variables.
280 *
281 * This function can be used like this:
282 * $token = ctools_set_variable_token('tabs');
283 *
284 * $token will then be a simple replacement for the 'tabs' about of the
285 * variables available in the page template.
286 */
287function ctools_set_variable_token($token) {
288 $string = '<!-- ctools-page-' . $token . ' -->';
289 ctools_set_page_token($string, 'variable', $token);
290 return $string;
291}
5e506485
EM
292
293/**
aeed3fef 294 * Easily set a token from the page variables.
5e506485 295 *
aeed3fef
SB
296 * This function can be used like this:
297 * $token = ctools_set_variable_token('id', 'mymodule_myfunction');
5e506485 298 */
aeed3fef
SB
299function ctools_set_callback_token($token, $callback) {
300 $string = '<!-- ctools-page-' . $token . ' -->';
301 ctools_set_page_token($string, 'callback', $callback);
302 return $string;
303}
5e506485 304
03045382
EM
305/**
306 * Tell CTools that sidebar blocks should not be rendered.
307 *
308 * It is often desirable to not display sidebars when rendering a page,
309 * particularly when using Panels. This informs CTools to alter out any
310 * sidebar regions during block render.
311 */
312function ctools_set_no_blocks($blocks = FALSE) {
313 $status = &drupal_static(__FUNCTION__, TRUE);
314 $status = $blocks;
315}
316
aeed3fef
SB
317// -----------------------------------------------------------------------
318// Drupal core hooks
319
320/**
321 * Implement hook_init to keep our global CSS at the ready.
322 */
323function ctools_init() {
324 ctools_add_css('ctools');
325 // If we are sure that CTools' AJAX is in use, change the error handling.
326 if (!empty($_REQUEST['ctools_ajax'])) {
327 ini_set('display_errors', 0);
328 register_shutdown_function('ctools_shutdown_handler');
329 }
330
331 // Clear plugin cache on the module page submit.
a40482ac 332 if ($_GET['q'] == 'admin/modules/list/confirm' && !empty($_POST)) {
aeed3fef
SB
333 cache_clear_all('ctools_plugin_files:', 'cache', TRUE);
334 }
335}
336
337/**
338 * Shutdown handler used during ajax operations to help catch fatal errors.
339 */
340function ctools_shutdown_handler() {
341 if (function_exists('error_get_last') AND ($error = error_get_last())){
342 switch($error['type']){
343 case E_ERROR:
344 case E_CORE_ERROR:
345 case E_COMPILE_ERROR:
346 case E_USER_ERROR:
347 // Do this manually because including files here is dangerous.
348 $commands = array(
349 array(
350 'command' => 'alert',
351 'title' => t('Error'),
352 'text' => t('Unable to complete operation. Fatal error in @file on line @line: @message', array(
353 '@file' => $error['file'],
354 '@line' => $error['line'],
355 '@message' => $error['message'],
356 )),
357 ),
358 );
359
360 // Change the status code so that the client will read the AJAX returned.
361 header('HTTP/1.1 200 OK');
362 drupal_json($commands);
363 }
5e506485
EM
364 }
365}
366
9398d6a6 367/**
0da7776f 368 * Implements hook_theme().
9398d6a6
EM
369 */
370function ctools_theme() {
aeed3fef 371 ctools_include('utility');
9398d6a6
EM
372 $items = array();
373 _ctools_passthrough($items, 'theme');
374 return $items;
375}
376
377/**
0da7776f 378 * Implements hook_menu().
25f97283 379 */
9398d6a6 380function ctools_menu() {
aeed3fef 381 ctools_include('utility');
9398d6a6
EM
382 $items = array();
383 _ctools_passthrough($items, 'menu');
384 return $items;
385}
25f97283 386
9398d6a6 387/**
aeed3fef
SB
388 * Implementation of hook_cron. Clean up old caches.
389 */
390function ctools_cron() {
391 ctools_include('utility');
392 _ctools_passthrough($items, 'cron');
393}
394
395/**
396 * Ensure the CTools CSS cache is flushed whenever hook_flush_caches is invoked.
9398d6a6 397 */
aeed3fef
SB
398function ctools_flush_caches() {
399 // Do not actually flush caches if running on cron. Drupal uses this hook
400 // in an inconsistent fashion and it does not necessarily mean to *flush*
401 // caches when running from cron. Instead it's just getting a list of cache
402 // tables and may not do any flushing.
403 if (variable_get('cron_semaphore', FALSE)) {
404 return;
9398d6a6 405 }
aeed3fef
SB
406
407 ctools_include('css');
408 ctools_css_flush_caches();
9398d6a6 409}
fe148241
EM
410
411/**
aeed3fef
SB
412 * Provide a search form with a different id so that form_alters will miss it
413 * and thus not get advanced search settings.
fe148241 414 */
aeed3fef
SB
415function ctools_forms() {
416 $forms['ctools_search_form']= array(
417 'callback' => 'search_form',
418 );
419
420 return $forms;
421}
422
423/**
424 * Implementation of hook_file_download()
425 *
426 * When using the private file system, we have to let Drupal know it's ok to
427 * download CSS and image files from our temporary directory.
428 */
429function ctools_file_download($filepath) {
430 if (strpos($filepath, 'ctools') === 0) {
431 $mime = file_get_mimetype($filepath);
432 // For safety's sake, we allow only text and images.
433 if (strpos($mime, 'text') === 0 || strpos($mime, 'image') === 0) {
434 return array('Content-type:' . $mime);
435 }
fe148241 436 }
aeed3fef
SB
437}
438
a40482ac
SB
439/**
440 * Implements hook_registry_files_alter().
441 *
442 * Alter the registry of files to automagically include all classes in
443 * class-based plugins.
444 */
445function ctools_registry_files_alter(&$files, $indexed_modules) {
446 ctools_include('registry');
447 return _ctools_registry_files_alter($files, $indexed_modules);
448}
449
aeed3fef
SB
450// -----------------------------------------------------------------------
451// CTools hook implementations.
452
453/**
454 * Implementation of hook_ctools_plugin_directory() to let the system know
455 * where all our own plugins are.
456 */
457function ctools_ctools_plugin_directory($owner, $plugin_type) {
458 if ($owner == 'ctools') {
459 return 'plugins/' . $plugin_type;
460 }
461}
462
463/**
a40482ac 464 * Implements hook_ctools_plugin_type().
aeed3fef 465 */
a40482ac
SB
466function ctools_ctools_plugin_type() {
467 ctools_include('utility');
468 $items = array();
469 // Add all the plugins that have their own declaration space elsewhere.
470 _ctools_passthrough($items, 'plugin-type');
471
472 return $items;
aeed3fef
SB
473}
474
475// -----------------------------------------------------------------------
476// Drupal theme preprocess hooks that must be in the .module file.
477
478/**
aeed3fef
SB
479 * A theme preprocess function to automatically allow panels-based node
480 * templates based upon input when the panel was configured.
481 */
482function ctools_preprocess_node(&$vars) {
483 // The 'panel_identifier' attribute of the node is added when the pane is
484 // rendered.
485 if (!empty($vars['node']->panel_identifier)) {
486 $vars['panel_identifier'] = check_plain($vars['node']->panel_identifier);
487 $vars['template_files'][] = 'node-panel-' . check_plain($vars['node']->panel_identifier);
488 }
489}
490
c140c9ad
EM
491function ctools_page_alter(&$page) {
492 $page['#post_render'][] = 'ctools_page_token_processing';
493}
494
aeed3fef 495/**
c140c9ad 496 * A theme post_render callback to allow content type plugins to use page
aeed3fef
SB
497 * template variables which are not yet available when the content type is
498 * rendered.
499 */
c140c9ad 500function ctools_page_token_processing($children, $elements) {
aeed3fef
SB
501 $tokens = ctools_set_page_token();
502 if (!empty($tokens)) {
503 foreach ($tokens as $token => $key) {
504 list($type, $argument) = $key;
505 switch ($type) {
506 case 'variable':
507 $tokens[$token] = isset($variables[$argument]) ? $variables[$argument] : '';
508 break;
509 case 'callback':
510 if (is_string($argument) && function_exists($argument)) {
511 $tokens[$token] = $argument($variables);
512 }
513 if (is_array($argument) && function_exists($argument[0])) {
514 $function = array_shift($argument);
515 $argument = array_merge(array(&$variables), $argument);
516 $tokens[$token] = call_user_func_array($function, $argument);
517 }
518 break;
519 }
520 }
c140c9ad 521 $children = strtr($children, $tokens);
aeed3fef 522 }
c140c9ad 523 return $children;
aeed3fef
SB
524}
525
526// -----------------------------------------------------------------------
527// Menu callbacks that must be in the .module file.
528
529/**
bb0ea4bb
EM
530 * Determine if the current user has access via a plugin.
531 *
532 * This function is meant to be embedded in the Drupal menu system, and
533 * therefore is in the .module file since sub files can't be loaded, and
534 * takes arguments a little bit more haphazardly than ctools_access().
535 *
efd617ba
EM
536 * @param $access
537 * An access control array which contains the following information:
538 * - 'logic': and or or. Whether all tests must pass or one must pass.
539 * - 'plugins': An array of access plugins. Each contains:
540 * - - 'name': The name of the plugin
541 * - - 'settings': The settings from the plugin UI.
542 * - - 'context': Which context to use.
bb0ea4bb
EM
543 * @param ...
544 * zero or more context arguments generated from argument plugins. These
545 * contexts must have an 'id' attached to them so that they can be
546 * properly associated. The argument plugin system should set this, but
547 * if the context is coming from elsewhere it will need to be set manually.
548 *
549 * @return
550 * TRUE if access is granted, false if otherwise.
551 */
efd617ba
EM
552function ctools_access_menu($access) {
553 // Short circuit everything if there are no access tests.
554 if (empty($access['plugins'])) {
555 return TRUE;
556 }
557
bb0ea4bb
EM
558 $contexts = array();
559 foreach (func_get_args() as $arg) {
560 if (is_object($arg) && get_class($arg) == 'ctools_context') {
561 $contexts[$arg->id] = $arg;
562 }
563 }
564
bb0ea4bb 565 ctools_include('context');
efd617ba 566 return ctools_access($access, $contexts);
bb0ea4bb 567}
f0b98e47
EM
568
569/**
aeed3fef
SB
570 * Determine if the current user has access via checks to multiple different
571 * permissions.
09811e62 572 *
aeed3fef
SB
573 * This function is a thin wrapper around user_access that allows multiple
574 * permissions to be easily designated for use on, for example, a menu callback.
09811e62 575 *
aeed3fef
SB
576 * @param ...
577 * An indexed array of zero or more permission strings to be checked by
578 * user_access().
579 *
580 * @return
581 * Iff all checks pass will this function return TRUE. If an invalid argument
582 * is passed (e.g., not a string), this function errs on the safe said and
583 * returns FALSE.
ee19aeef 584 */
aeed3fef
SB
585function ctools_access_multiperm() {
586 foreach (func_get_args() as $arg) {
587 if (!is_string($arg) || !user_access($arg)) {
588 return FALSE;
589 }
ee19aeef 590 }
aeed3fef 591 return TRUE;
0baa731a 592}
5e8dada0
EM
593
594/**
595 * Check to see if the incoming menu item is js capable or not.
596 *
597 * This can be used as %ctools_js as part of a path in hook menu. CTools
598 * ajax functions will automatically change the phrase 'nojs' to 'ajax'
599 * when it attaches ajax to a link. This can be used to autodetect if
600 * that happened.
601 */
602function ctools_js_load($js) {
603 if ($js == 'ajax') {
604 return TRUE;
605 }
606 return 0;
607}
94976edc
EM
608
609/**
aeed3fef
SB
610 * Menu _load hook.
611 *
612 * This function will be called to load an object as a replacement for
613 * %ctools_export_ui in menu paths.
94976edc 614 */
aeed3fef 615function ctools_export_ui_load($item_name, $plugin_name) {
a40482ac 616 $return = &drupal_static(__FUNCTION__, FALSE);
aeed3fef
SB
617
618 if (!$return) {
619 ctools_include('export-ui');
620 $plugin = ctools_get_export_ui($plugin_name);
621
622 if ($plugin) {
623 // Get the load callback.
624 $item = ctools_export_crud_load($plugin['schema'], $item_name);
625 return empty($item) ? FALSE : $item;
94976edc
EM
626 }
627 }
aeed3fef
SB
628
629 return $return;
94976edc
EM
630}
631
aeed3fef
SB
632// -----------------------------------------------------------------------
633// Caching callbacks on behalf of export-ui.
634
94976edc 635/**
aeed3fef 636 * Menu access callback for various tasks of export-ui.
94976edc 637 */
aeed3fef
SB
638function ctools_export_ui_task_access($plugin_name, $op, $item = NULL) {
639 ctools_include('export-ui');
640 $plugin = ctools_get_export_ui($plugin_name);
641 $handler = ctools_export_ui_get_handler($plugin);
94976edc 642
aeed3fef
SB
643 if ($handler) {
644 return $handler->access($op, $item);
94976edc
EM
645 }
646
aeed3fef
SB
647 // Deny access if the handler cannot be found.
648 return FALSE;
1468ce22
EM
649}
650
651/**
aeed3fef 652 * Cache callback on behalf of ctools_export_ui.
1468ce22 653 */
aeed3fef 654function ctools_export_ui_context_cache_get($plugin_name, $key) {
a40482ac
SB
655 dsm('should not be called!');
656 return;
1468ce22
EM
657}
658
659/**
aeed3fef 660 * Cache callback on behalf of ctools_export_ui.
1468ce22 661 */
aeed3fef 662function ctools_export_ui_context_cache_set($plugin_name, $key, $item) {
a40482ac
SB
663 dsm('should not be called!');
664 return;
1468ce22 665}
2300958d
EM
666
667/**
aeed3fef
SB
668 * Callback for access control ajax form on behalf of export ui.
669 *
670 * Returns the cached access config and contexts used.
671 * Note that this is assuming that access will be in $item->access -- if it
672 * is not, an export UI plugin will have to make its own callbacks.
2300958d 673 */
aeed3fef
SB
674function ctools_export_ui_ctools_access_get($argument) {
675 ctools_include('export-ui');
a40482ac 676 list($plugin_name, $key) = explode(':', $argument, 2);
aeed3fef
SB
677
678 $plugin = ctools_get_export_ui($plugin_name);
679 $handler = ctools_export_ui_get_handler($plugin);
680
681 if ($handler) {
682 ctools_include('context');
683 $item = $handler->edit_cache_get($key);
684 if (!$item) {
685 $item = ctools_export_crud_load($handler->plugin['schema'], $key);
686 }
2300958d 687
aeed3fef
SB
688 $contexts = ctools_context_load_contexts($item);
689 return array($item->access, $contexts);
690 }
691}
692
693/**
694 * Callback for access control ajax form on behalf of export ui
695 *
696 * Returns the cached access config and contexts used.
697 * Note that this is assuming that access will be in $item->access -- if it
698 * is not, an export UI plugin will have to make its own callbacks.
699 */
700function ctools_export_ui_ctools_access_set($argument, $access) {
701 ctools_include('export-ui');
a40482ac 702 list($plugin_name, $key) = explode(':', $argument, 2);
aeed3fef
SB
703
704 $plugin = ctools_get_export_ui($plugin_name);
705 $handler = ctools_export_ui_get_handler($plugin);
706
707 if ($handler) {
708 ctools_include('context');
709 $item = $handler->edit_cache_get($key);
710 if (!$item) {
711 $item = ctools_export_crud_load($handler->plugin['schema'], $key);
712 }
713 $item->access = $access;
714 return $handler->edit_cache_set_key($item, $key);
715 }
2300958d 716}
a40482ac
SB
717
718/**
719 * Implements hook_menu_local_tasks_alter().
720 */
721function ctools_menu_local_tasks_alter(&$data, $router_item, $root_path) {
722 ctools_include('menu');
723 _ctools_menu_add_dynamic_items($data, $router_item, $root_path);
724}
03045382
EM
725
726/**
727 * Implement hook_block_list_alter() to potentially remove blocks.
728 *
729 * This exists in order to replicate Drupal 6's "no blocks" functionality.
730 */
731function ctools_block_list_alter(&$blocks) {
732 $check = drupal_static('ctools_set_no_blocks', TRUE);
733 if (!$check) {
734 foreach ($blocks as $block_id => $block) {
735 // @todo -- possibly we can set configuration for this so that users can
736 // specify which blocks will not get rendered.
737 if (substr_compare($block->region, 'sidebar', 0)) {
738 unset($blocks[$block_id]);
739 }
740 }
741 }
742}
743
90720abe
EM
744/**
745 * Implement hook_modules_enabled to clear static caches for detecting new plugins
746 */
747function ctools_modules_enabled($modules) {
748 ctools_include('plugins');
749 ctools_get_plugins_reset();
750}