ctools.module

Tracking 7.x-1.x branch
  1. drupal
    1. 6 contributions/ctools/ctools.module
    2. 7 contributions/ctools/ctools.module

CTools primary module file.

Most of the CTools tools are in their own .inc files. This contains nothing more than a few convenience functions and some hooks that must be implemented in the module file.

Functions & methods

NameDescription
ctools_access_menuDetermine if the current user has access via a plugin.
ctools_access_multipermDetermine if the current user has access via checks to multiple different permissions.
ctools_add_cssInclude css files as necessary.
ctools_add_jsInclude js files as necessary.
ctools_ajax_theme_callbackMenu theme callback.
ctools_api_versionTest the CTools API version.
ctools_attach_cssFormat a css file name for use with $form['#attached']['css'].
ctools_attach_jsFormat a javascript file name for use with $form['#attached']['js'].
ctools_block_list_alterImplement hook_block_list_alter() to potentially remove blocks.
ctools_break_phrase
ctools_cronImplementation of hook_cron. Clean up old caches.
ctools_ctools_entity_context_alter
ctools_ctools_plugin_directoryImplementation of hook_ctools_plugin_directory() to let the system know where all our own plugins are.
ctools_ctools_plugin_typeImplements hook_ctools_plugin_type().
ctools_element_info_alterImplements hook_element_info_alter().
ctools_export_ui_context_cache_getCache callback on behalf of ctools_export_ui.
ctools_export_ui_context_cache_setCache callback on behalf of ctools_export_ui.
ctools_export_ui_ctools_access_getCallback for access control ajax form on behalf of export ui.
ctools_export_ui_ctools_access_setCallback for access control ajax form on behalf of export ui
ctools_export_ui_loadMenu _load hook.
ctools_export_ui_task_accessMenu access callback for various tasks of export-ui.
ctools_file_downloadImplementation of hook_file_download()
ctools_flush_cachesEnsure the CTools CSS cache is flushed whenever hook_flush_caches is invoked.
ctools_form_includeInclude .inc files in a form context.
ctools_form_include_fileAdd an arbitrary path to the $form_state so it can work with form cache.
ctools_get_rolesGet a list of roles in the system.
ctools_image_pathProvide the proper path to an image as necessary.
ctools_includeInclude .inc files as necessary.
ctools_initImplement hook_init to keep our global CSS at the ready.
ctools_js_loadCheck to see if the incoming menu item is js capable or not.
ctools_menuImplements hook_menu().
ctools_menu_local_tasks_alterImplements hook_menu_local_tasks_alter().
ctools_modules_enabledImplement hook_modules_enabled to clear static caches for detecting new plugins
ctools_page_alter
ctools_page_token_processingA theme post_render callback to allow content type plugins to use page template variables which are not yet available when the content type is rendered.
ctools_preprocess_nodeA theme preprocess function to automatically allow panels-based node templates based upon input when the panel was configured.
ctools_registry_files_alterImplements hook_registry_files_alter().
ctools_set_callback_tokenEasily set a token from the page variables.
ctools_set_no_blocksTell CTools that sidebar blocks should not be rendered.
ctools_set_page_tokenSet a token/value pair to be replaced later in the request, specifically in ctools_preprocess_page().
ctools_set_variable_tokenEasily set a token from the page variables.
ctools_shutdown_handlerShutdown handler used during ajax operations to help catch fatal errors.
ctools_themeImplements hook_theme().

Constants

NameDescription
CTOOLS_API_VERSION

File

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