panels_mini.module 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482
  1. <?php
  2. /**
  3. * @file panels_mini.module
  4. *
  5. * This module provides mini panels which are basically panels that can be
  6. * used within blocks or other panels.
  7. */
  8. /**
  9. * Implementation of hook_permission().
  10. */
  11. function panels_mini_permission() {
  12. return array(
  13. 'create mini panels' => array(
  14. 'title' => t('Create mini panels'),
  15. 'description' => t('Create new mini panels'),
  16. ),
  17. 'administer mini panels' => array(
  18. 'title' => t('Administer mini panels'),
  19. 'description' => t('Edit and delete mini panels'),
  20. ),
  21. );
  22. }
  23. /**
  24. * Implementation of hook_menu().
  25. */
  26. function panels_mini_menu() {
  27. // Safety: go away if CTools is not at an appropriate version.
  28. if (!defined('PANELS_REQUIRED_CTOOLS_API') || !module_invoke('ctools', 'api_version', PANELS_REQUIRED_CTOOLS_API)) {
  29. return array();
  30. }
  31. $items['admin/structure/mini-panels/settings'] = array(
  32. 'title' => 'Settings',
  33. 'page callback' => 'panels_mini_settings',
  34. 'access arguments' => array('create mini panels'),
  35. 'type' => MENU_LOCAL_TASK,
  36. );
  37. // Also provide settings on the main panel UI
  38. $items['admin/structure/panels/settings/panels-mini'] = array(
  39. 'title' => 'Mini panels',
  40. 'page callback' => 'panels_mini_settings',
  41. 'access arguments' => array('create mini panels'),
  42. 'type' => MENU_LOCAL_TASK,
  43. );
  44. return $items;
  45. }
  46. /**
  47. * Settings for mini panels.
  48. */
  49. function panels_mini_settings() {
  50. ctools_include('common', 'panels');
  51. return drupal_get_form('panels_common_settings', 'panels_mini');
  52. }
  53. // ---------------------------------------------------------------------------
  54. // Allow the rest of the system access to mini panels
  55. /**
  56. * Implementation of hook_block_info().
  57. */
  58. function panels_mini_block_info() {
  59. // Safety: go away if CTools is not at an appropriate version.
  60. if (!defined('PANELS_REQUIRED_CTOOLS_API') || !module_invoke('ctools', 'api_version', PANELS_REQUIRED_CTOOLS_API)) {
  61. return array();
  62. }
  63. $blocks = array();
  64. $minis = panels_mini_load_all();
  65. foreach ($minis as $panel_mini) {
  66. if (empty($panel_mini->disabled) && (module_exists('page_manager') || empty($panel_mini->requiredcontexts))) {
  67. $blocks[$panel_mini->name] = array(
  68. 'info' => t('Mini panel: "@title"', array('@title' => $panel_mini->admin_title)),
  69. 'cache' => DRUPAL_NO_CACHE,
  70. );
  71. }
  72. }
  73. return $blocks;
  74. }
  75. /**
  76. * Implementation of hook_block_view().
  77. *
  78. * @see panels_mini_panels_mini_content_type_render().
  79. */
  80. function panels_mini_block_view($delta = 0) {
  81. // static recursion protection.
  82. static $viewing = array();
  83. if (!empty($viewing[$delta])) {
  84. return;
  85. }
  86. $viewing[$delta] = TRUE;
  87. $panel_mini = panels_mini_load($delta);
  88. if (empty($panel_mini)) {
  89. // Bail out early if the specified mini panel doesn't exist.
  90. return;
  91. }
  92. ctools_include('context');
  93. $contexts = array();
  94. if (module_exists('page_manager') && $current_page = page_manager_get_current_page()) {
  95. if (!empty($current_page['contexts'])) {
  96. $contexts = ctools_context_match_required_contexts($panel_mini->requiredcontexts, $current_page['contexts']);
  97. }
  98. }
  99. $panel_mini->context = $panel_mini->display->context = ctools_context_load_contexts($panel_mini, FALSE, $contexts);
  100. $panel_mini->display->css_id = panels_mini_get_id($panel_mini->name);
  101. $block = array();
  102. $block['content'] = panels_render_display($panel_mini->display);
  103. $block['subject'] = $panel_mini->display->get_title();
  104. unset($viewing[$delta]);
  105. return $block;
  106. }
  107. /**
  108. * Implementation of hook_block_configure().
  109. */
  110. function panels_mini_block_configure($delta = 0) {
  111. return array(
  112. 'admin_shortcut' => array(
  113. '#markup' => l(t('Manage this mini-panel'), 'admin/structure/mini-panels/list/' . $delta . '/edit')
  114. ),
  115. );
  116. }
  117. /**
  118. * Implements hook_block_list_alter().
  119. *
  120. * Remove the block if the required contexts are not available.
  121. */
  122. function panels_mini_block_list_alter(&$blocks) {
  123. if (module_exists('page_manager')) {
  124. $current_page = page_manager_get_current_page();
  125. }
  126. foreach ($blocks as $key => $block) {
  127. if ($block->module != 'panels_mini') {
  128. // This block was added by a contrib module, leave it in the list.
  129. continue;
  130. }
  131. $panel_mini = panels_mini_load($block->delta);
  132. if (empty($panel_mini)) {
  133. // Bail out early if the specified mini panel doesn't exist.
  134. unset($blocks[$key]);
  135. continue;
  136. }
  137. if (!empty($panel_mini->requiredcontexts)) {
  138. if (!$current_page || empty($current_page['contexts'])) {
  139. unset($blocks[$key]);
  140. continue;
  141. }
  142. else {
  143. $required = array();
  144. foreach ($panel_mini->requiredcontexts as $context) {
  145. $info = ctools_get_context($context['name']);
  146. $required[] = new ctools_context_required($context['identifier'], $info['context name']);
  147. }
  148. if (!ctools_context_match_requirements($current_page['contexts'], $required)) {
  149. unset($blocks[$key]);
  150. continue;
  151. }
  152. }
  153. }
  154. }
  155. }
  156. /**
  157. * Statically store all used IDs to ensure all mini panels get a unique id.
  158. */
  159. function panels_mini_get_id($name) {
  160. $id_cache = &drupal_static(__FUNCTION__, array());
  161. $id = 'mini-panel-' . $name;
  162. if (!empty($id_cache[$name])) {
  163. $id .= "-" . $id_cache[$name]++;
  164. }
  165. else {
  166. $id_cache[$name] = 1;
  167. }
  168. return $id;
  169. }
  170. // ---------------------------------------------------------------------------
  171. // Database functions.
  172. /**
  173. * Create a new page with defaults appropriately set from schema.
  174. */
  175. function panels_mini_new($set_defaults = TRUE) {
  176. ctools_include('export');
  177. return ctools_export_new_object('panels_mini', $set_defaults);
  178. }
  179. /**
  180. * Load a single mini panel.
  181. */
  182. function panels_mini_load($name) {
  183. $cache = &drupal_static('panels_mini_load_all', array());
  184. // We use array_key_exists because failed loads will be NULL and
  185. // isset() will try to load it again.
  186. if (!array_key_exists($name, $cache)) {
  187. ctools_include('export');
  188. $result = ctools_export_load_object('panels_mini', 'names', array($name));
  189. if (isset($result[$name])) {
  190. if (empty($result[$name]->display)) {
  191. $result[$name]->display = panels_load_display($result[$name]->did);
  192. if (!empty($result[$name]->title) && empty($result[$name]->display->title)) {
  193. $result[$name]->display->title = $result[$name]->title;
  194. }
  195. }
  196. $cache[$name] = $result[$name];
  197. if (!empty($result[$name]->title) && empty($result[$name]->admin_title)) {
  198. $cache[$name]->admin_title = $result[$name]->title;
  199. }
  200. }
  201. else {
  202. $cache[$name] = NULL;
  203. }
  204. }
  205. if (isset($cache[$name])) {
  206. return $cache[$name];
  207. }
  208. }
  209. /**
  210. * Load all mini panels.
  211. */
  212. function panels_mini_load_all($reset = FALSE) {
  213. $cache = &drupal_static('panels_mini_load_all', array());
  214. static $all_loaded = FALSE;
  215. // We check our own private static because individual minis could have
  216. // been loaded prior to load all and we need to know that.
  217. if (!$all_loaded || $reset) {
  218. $all_loaded = TRUE;
  219. if ($reset) {
  220. $cache = array();
  221. }
  222. ctools_include('export');
  223. $minis = ctools_export_load_object('panels_mini');
  224. $dids = array();
  225. foreach ($minis as $mini) {
  226. if (empty($cache[$mini->name])) {
  227. if (!empty($mini->did)) {
  228. $dids[$mini->did] = $mini->name;
  229. }
  230. else {
  231. // Translate old style titles into new titles.
  232. if (!empty($mini->title) && empty($mini->display->title)) {
  233. $mini->display->title = $mini->title;
  234. }
  235. }
  236. // Translate old style titles into new titles.
  237. if (isset($mini->title) && empty($mini->admin_title)) {
  238. $mini->admin_title = $mini->title;
  239. }
  240. $cache[$mini->name] = $mini;
  241. }
  242. }
  243. $displays = panels_load_displays(array_keys($dids));
  244. foreach ($displays as $did => $display) {
  245. if (!empty($cache[$dids[$did]]->title) && empty($display->title)) {
  246. $display->title = $cache[$dids[$did]]->title;
  247. }
  248. $cache[$dids[$did]]->display = $display;
  249. }
  250. }
  251. // Strip out NULL entries that may have been added by panels_mini_load().
  252. return array_filter($cache);
  253. }
  254. /**
  255. * Write a mini panel to the database.
  256. */
  257. function panels_mini_save(&$mini) {
  258. if (!empty($mini->display)) {
  259. $display = panels_save_display($mini->display);
  260. $mini->did = $display->did;
  261. }
  262. $update = (isset($mini->pid) && $mini->pid != 'new') ? array('pid') : array();
  263. drupal_write_record('panels_mini', $mini, $update);
  264. return $mini;
  265. }
  266. /**
  267. * Remove a mini panel.
  268. */
  269. function panels_mini_delete($mini) {
  270. db_delete('panels_mini')
  271. ->condition('name', $mini->name)
  272. ->execute();
  273. if (db_table_exists('block') && $mini->type != t('Overridden')) {
  274. // Also remove from block table as long as there isn't a default that may appear.
  275. db_delete('block')
  276. ->condition('delta', $mini->name)
  277. ->condition('module', 'panels_mini')
  278. ->execute();
  279. }
  280. return panels_delete_display($mini->did);
  281. }
  282. /**
  283. * Export a mini panel.
  284. */
  285. function panels_mini_export($mini, $indent = '') {
  286. ctools_include('export');
  287. $output = ctools_export_object('panels_mini', $mini, $indent);
  288. // Export the primary display
  289. $display = !empty($mini->display) ? $mini->display : panels_load_display($mini->did);
  290. $output .= panels_export_display($display, $indent);
  291. $output .= $indent . '$mini->display = $display' . ";\n";
  292. return $output;
  293. }
  294. /**
  295. * Remove the block version of mini panels from being available content types.
  296. */
  297. function panels_mini_ctools_block_info($module, $delta, &$info) {
  298. $info = NULL;
  299. }
  300. /**
  301. * Implementation of hook_ctools_plugin_directory() to let the system know
  302. * we implement task and task_handler plugins.
  303. */
  304. function panels_mini_ctools_plugin_directory($module, $plugin) {
  305. if ($module == 'ctools' && ($plugin == 'content_types' || $plugin == 'export_ui')) {
  306. return 'plugins/' . $plugin;
  307. }
  308. }
  309. /**
  310. * Get the display cache for the panels_mini plugin.
  311. */
  312. function _panels_mini_panels_cache_get($key) {
  313. ctools_include('export-ui');
  314. $plugin = ctools_get_export_ui('panels_mini');
  315. $handler = ctools_export_ui_get_handler($plugin);
  316. if (!$handler) {
  317. return;
  318. }
  319. $item = $handler->edit_cache_get($key);
  320. if (!$item) {
  321. $item = ctools_export_crud_load($handler->plugin['schema'], $key);
  322. }
  323. return array($handler, $item);
  324. }
  325. /**
  326. * Get display edit cache for the panels mini export UI
  327. *
  328. * The key is the second half of the key in this form:
  329. * panels_mini:TASK_NAME:HANDLER_NAME;
  330. */
  331. function panels_mini_panels_cache_get($key) {
  332. ctools_include('common', 'panels');
  333. list($handler, $item) = _panels_mini_panels_cache_get($key);
  334. if (isset($item->mini_panels_display_cache)) {
  335. return $item->mini_panels_display_cache;
  336. }
  337. $cache = new stdClass();
  338. $cache->display = $item->display;
  339. $cache->display->context = ctools_context_load_contexts($item);
  340. $cache->display->cache_key = 'panels_mini:' . $key;
  341. $cache->content_types = panels_common_get_allowed_types('panels_mini', $cache->display->context);
  342. $cache->display_title = TRUE;
  343. // @TODO support locking
  344. $cache->locked = FALSE;
  345. return $cache;
  346. }
  347. /**
  348. * Store a display edit in progress in the page cache.
  349. */
  350. function panels_mini_panels_cache_set($key, $cache) {
  351. list($handler, $item) = _panels_mini_panels_cache_get($key);
  352. $item->mini_panels_display_cache = $cache;
  353. $handler->edit_cache_set_key($item, $key);
  354. }
  355. /**
  356. * Save all changes made to a display using the panels mini UI cache.
  357. */
  358. function panels_mini_panels_cache_clear($key, $cache) {
  359. list($handler, $item) = _panels_mini_panels_cache_get($key);
  360. $handler->edit_cache_clear($item);
  361. }
  362. /**
  363. * Save all changes made to a display using the panels mini UI cache.
  364. */
  365. function panels_mini_panels_cache_save($key, $cache) {
  366. list($handler, $item) = _panels_mini_panels_cache_get($key);
  367. $item->display = $cache->display;
  368. panels_mini_save($item);
  369. $handler->edit_cache_clear($item);
  370. }
  371. /**
  372. * Break the lock on a panels mini page.
  373. */
  374. function panels_mini_panels_cache_break_lock($key, $cache) {
  375. }
  376. /**
  377. * Implementation of hook_panels_dashboard_blocks().
  378. *
  379. * Adds mini panels information to the Panels dashboard.
  380. */
  381. function panels_mini_panels_dashboard_blocks(&$vars) {
  382. $vars['links']['panels_mini'] = array(
  383. 'title' => l(t('Mini panel'), 'admin/structure/mini-panels/add'),
  384. 'description' => t('Mini panels are small content areas exposed as blocks, for when you need to have complex block layouts or layouts within layouts.'),
  385. 'weight' => -1,
  386. );
  387. // Load all mini panels and their displays.
  388. $panel_minis = panels_mini_load_all();
  389. $count = 0;
  390. $rows = array();
  391. foreach ($panel_minis as $panel_mini) {
  392. $rows[] = array(
  393. check_plain($panel_mini->admin_title),
  394. array(
  395. 'data' => l(t('Edit'), "admin/structure/mini-panels/list/$panel_mini->name/edit"),
  396. 'class' => 'links',
  397. ),
  398. );
  399. // Only show 10.
  400. if (++$count >= 10) {
  401. break;
  402. }
  403. }
  404. if ($rows) {
  405. $content = theme('table', array('rows' => $rows, 'attributes' => array('class' => 'panels-manage')));
  406. }
  407. else {
  408. $content = '<p>' . t('There are no mini panels.') . '</p>';
  409. }
  410. $vars['blocks']['panels_mini'] = array(
  411. 'weight' => -100,
  412. 'title' => t('Manage mini panels'),
  413. 'link' => l(t('Go to list'), 'admin/structure/mini-panels'),
  414. 'content' => $content,
  415. 'class' => 'dashboard-mini-panels',
  416. 'section' => 'left',
  417. );
  418. }