views_panes.inc 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520
  1. <?php
  2. /**
  3. * @file
  4. * Content type plugin to allow Views to be exposed as a display type,
  5. * leaving most of the configuration on the view.
  6. */
  7. /**
  8. * Implements hook_ctools_content_types()
  9. */
  10. function views_content_views_panes_ctools_content_types() {
  11. return array(
  12. 'title' => t('View panes'),
  13. 'admin settings' => 'views_content_admin_form',
  14. 'all contexts' => TRUE,
  15. );
  16. }
  17. /**
  18. * Return all content types available.
  19. */
  20. function views_content_views_panes_content_type_content_types($plugin) {
  21. $types = array();
  22. // It can be fairly intensive to calculate this, so let's cache this in the
  23. // cache_views table. The nice thing there is that if views ever change, that
  24. // table will always be cleared. Except for the occasional default view, so
  25. // we must use the Views caching functions in order to respect Views caching
  26. // settings.
  27. views_include('cache');
  28. $data = views_cache_get('views_content_panes', TRUE);
  29. if (!empty($data->data)) {
  30. $types = $data->data;
  31. }
  32. if (empty($types)) {
  33. $types = array();
  34. $views = views_get_all_views();
  35. foreach ($views as $view) {
  36. if (!empty($view->disabled)) {
  37. continue;
  38. }
  39. $view->init_display();
  40. foreach ($view->display as $id => $display) {
  41. if (empty($display->handler->panel_pane_display)) {
  42. continue;
  43. }
  44. $info = _views_content_panes_content_type($view, $display);
  45. if ($info) {
  46. $types[$view->name . '-' . $id] = $info;
  47. }
  48. }
  49. $view->destroy();
  50. }
  51. views_cache_set('views_content_panes', $types, TRUE);
  52. }
  53. return $types;
  54. }
  55. /**
  56. * Return a single content type.
  57. */
  58. function views_content_views_panes_content_type_content_type($subtype, $plugin) {
  59. list($name, $display) = explode('-', $subtype);
  60. $view = views_get_view($name);
  61. if (empty($view)) {
  62. return;
  63. }
  64. $view->set_display($display);
  65. $retval = _views_content_panes_content_type($view, $view->display[$display]);
  66. $view->destroy();
  67. return $retval;
  68. }
  69. function _views_content_panes_content_type($view, $display) {
  70. // Ensure the handler is the right type, as Views will fall back to
  71. // the default display if something is broken:
  72. if (!is_a($display->handler, 'views_content_plugin_display_panel_pane')) {
  73. return;
  74. }
  75. $title = views_content_get_display_title($view, $display->id);
  76. $description = $display->handler->get_option('pane_description');
  77. if (!$description) {
  78. $description = $view->description;
  79. }
  80. $category = $display->handler->get_option('pane_category');
  81. if (!$category['name']) {
  82. $category['name'] = t('View panes');
  83. }
  84. $icon = 'icon_views_page.png';
  85. $contexts = array();
  86. $arguments = $display->handler->get_argument_input();
  87. ctools_include('views');
  88. foreach ($arguments as $argument) {
  89. $contexts[] = ctools_views_get_argument_context($argument);
  90. }
  91. $allow = $display->handler->get_option('allow');
  92. return array(
  93. 'title' => $title,
  94. 'icon' => $icon,
  95. 'description' => filter_xss_admin($description),
  96. 'required context' => $contexts,
  97. 'category' => array($category['name'], $category['weight']),
  98. 'no title override' => empty($allow['title_override']),
  99. );
  100. }
  101. /**
  102. * Output function for the 'views' content type.
  103. *
  104. * Outputs a view based on the module and delta supplied in the configuration.
  105. */
  106. function views_content_views_panes_content_type_render($subtype, $conf, $panel_args, $contexts) {
  107. if (!is_array($contexts)) {
  108. $contexts = array($contexts);
  109. }
  110. list($name, $display) = explode('-', $subtype);
  111. $view = views_get_view($name);
  112. if (empty($view)) {
  113. return;
  114. }
  115. $view->set_display($display);
  116. views_content_views_panes_add_defaults($conf, $view);
  117. if (!$view->display_handler->access($GLOBALS['user']) || empty($view->display_handler->panel_pane_display)) {
  118. return;
  119. }
  120. $conf['pane_contexts'] = $contexts;
  121. $conf['panel_args'] = $panel_args;
  122. $view->display_handler->set_pane_conf($conf);
  123. $allow = $view->display_handler->get_option('allow');
  124. if ($allow['path_override'] && !empty($conf['path'])) {
  125. $view->override_path = $conf['path'];
  126. }
  127. else if ($path = $view->display_handler->get_option('inherit_panels_path')) {
  128. $view->override_path = $_GET['q'];
  129. }
  130. $block = new stdClass();
  131. $block->module = 'views';
  132. $block->delta = $view->name . '-' . $display;
  133. if (($allow['link_to_view'] && !empty($conf['link_to_view'])) ||
  134. (!$allow['link_to_view'] && $view->display_handler->get_option('link_to_view'))) {
  135. $block->title_link = $view->get_url();
  136. }
  137. $stored_feeds = drupal_add_feed();
  138. $block->content = $view->preview();
  139. if (empty($view->result) && !$view->display_handler->get_option('empty') && empty($view->style_plugin->definition['even empty'])) {
  140. return;
  141. }
  142. // Add contextual links to the output.
  143. $block = (array) $block;
  144. views_add_block_contextual_links($block, $view, $display, 'panel_pane');
  145. $block = (object) $block;
  146. $block->title = $view->get_title();
  147. if (empty($view->total_rows) || $view->total_rows <= $view->get_items_per_page()) {
  148. unset($block->more);
  149. }
  150. if ((!empty($allow['feed_icons']) && !empty($conf['feed_icons'])) ||
  151. (empty($allow['feed_icons']) && $view->display_handler->get_option('feed_icons'))) {
  152. $new_feeds = drupal_add_feed();
  153. if ($diff = array_diff(array_keys($new_feeds), array_keys($stored_feeds))) {
  154. foreach ($diff as $url) {
  155. $block->feeds[$url] = $new_feeds[$url];
  156. }
  157. }
  158. }
  159. return $block;
  160. }
  161. /**
  162. * Add defaults to view pane settings.
  163. * This helps cover us if $allow settings changed and there are no actual
  164. * settings for a particular item.
  165. */
  166. function views_content_views_panes_add_defaults(&$conf, $view) {
  167. $pager = $view->display_handler->get_option('pager');
  168. if (empty($conf)) {
  169. $conf = array();
  170. }
  171. $conf += array(
  172. 'link_to_view' => $view->display_handler->get_option('link_to_view'),
  173. 'more_link' => $view->display_handler->get_option('use_more'),
  174. 'feed_icons' => FALSE,
  175. 'use_pager' => $pager['type'] != 'none' && $pager['type'] != 'some',
  176. 'pager_id' => isset($pager['options']['id']) ? $pager['options']['id'] : 0,
  177. 'items_per_page' => !empty($pager['options']['items_per_page']) ? $pager['options']['items_per_page'] : 10,
  178. 'offset' => !empty($pager['options']['offset']) ? $pager['options']['offset'] : 0,
  179. 'path_override' => FALSE,
  180. 'path' => $view->get_path(),
  181. 'fields_override' => $view->display_handler->get_option('fields_override'),
  182. );
  183. }
  184. /**
  185. * Returns an edit form for a block.
  186. */
  187. function views_content_views_panes_content_type_edit_form($form, &$form_state) {
  188. $conf = $form_state['conf'];
  189. $contexts = $form_state['contexts'];
  190. // This allows older content to continue to work, where we used to embed
  191. // the display directly.
  192. list($name, $display_id) = explode('-', $form_state['subtype_name']);
  193. $view = views_get_view($name);
  194. if (empty($view)) {
  195. $form['markup'] = array('#markup' => t('Broken/missing/deleted view.'));
  196. return $form;
  197. }
  198. $view->set_display($display_id);
  199. // If it couldn't set the display and we got the default display instead,
  200. // fail.
  201. if ($view->current_display == 'default') {
  202. $form['markup'] = array('#markup' => t('Broken/missing/deleted view display.'));
  203. return $form;
  204. }
  205. $allow = $view->display_handler->get_option('allow');
  206. // Provide defaults for everything in order to prevent warnings.
  207. views_content_views_panes_add_defaults($conf, $view);
  208. $form['arguments']['#tree'] = TRUE;
  209. foreach ($view->display_handler->get_argument_input() as $id => $argument) {
  210. if ($argument['type'] == 'user') {
  211. $form['arguments'][$id] = array(
  212. '#type' => 'textfield',
  213. '#default_value' => isset($conf['arguments'][$id]) ? $conf['arguments'][$id] : '',
  214. '#description' => t('You may use keywords for substitutions.'),
  215. '#title' => check_plain($argument['label']),
  216. );
  217. }
  218. }
  219. if ($allow['link_to_view'] ) {
  220. $form['link_to_view'] = array(
  221. '#type' => 'checkbox',
  222. '#default_value' => isset($conf['link_to_view']) ? $conf['link_to_view'] : $view->display_handler->get_option('link_to_view'),
  223. '#title' => t('Link title to page'),
  224. );
  225. }
  226. if ($allow['more_link']) {
  227. $form['more_link'] = array(
  228. '#type' => 'checkbox',
  229. '#default_value' => isset($conf['more_link']) ? $conf['more_link'] : $view->display_handler->get_option('use_more'),
  230. '#description' => t('The text of this link will be "@more". This setting can only be modified on the View configuration.', array('@more' => $view->display_handler->use_more_text())),
  231. '#title' => t('Provide a "more" link.'),
  232. );
  233. }
  234. if (!empty($allow['feed_icons'])) {
  235. $form['feed_icons'] = array(
  236. '#type' => 'checkbox',
  237. '#default_value' => !empty($conf['feed_icons']),
  238. '#title' => t('Display feed icons'),
  239. );
  240. }
  241. $view->init_style();
  242. if ($allow['fields_override'] && $view->style_plugin->uses_fields()) {
  243. $form['fields_override'] = array(
  244. '#type' => 'fieldset',
  245. '#title' => 'Fields to display',
  246. '#collapsible' => TRUE,
  247. '#tree' => TRUE,
  248. );
  249. foreach ($view->display_handler->get_handlers('field') as $field => $handler) {
  250. $title = $handler->ui_name();
  251. if ($handler->options['label']) {
  252. $title .= ' (' . check_plain($handler->options['label']) . ')';
  253. }
  254. $form['fields_override'][$field] = array(
  255. '#type' => 'checkbox',
  256. '#title' => $title,
  257. '#default_value' => isset($conf['fields_override'][$field]) ? $conf['fields_override'][$field] : !$handler->options['exclude'],
  258. );
  259. }
  260. }
  261. ctools_include('dependent');
  262. if ($allow['use_pager']) {
  263. $form['use_pager'] = array(
  264. '#type' => 'checkbox',
  265. '#title' => t('Use pager'),
  266. '#default_value' => $conf['use_pager'],
  267. '#id' => 'use-pager-checkbox',
  268. '#prefix' => '<div class="container-inline">',
  269. );
  270. $form['pager_id'] = array(
  271. '#type' => 'textfield',
  272. '#default_value' => $conf['pager_id'],
  273. '#title' => t('Pager ID'),
  274. '#size' => 4,
  275. '#id' => 'use-pager-textfield',
  276. '#dependency' => array('use-pager-checkbox' => array(1)),
  277. '#suffix' => '</div>',
  278. );
  279. }
  280. if ($allow['items_per_page']) {
  281. $form['items_per_page'] = array(
  282. '#type' => 'textfield',
  283. '#default_value' => $conf['items_per_page'],
  284. '#title' => t('Num items'),
  285. '#size' => 4,
  286. '#description' => t('Select the number of items to display, or 0 to display all results.'),
  287. );
  288. }
  289. if ($allow['offset']) {
  290. $form['offset'] = array(
  291. '#type' => 'textfield',
  292. '#default_value' => $conf['offset'],
  293. '#title' => t('Offset'),
  294. '#size' => 4,
  295. '#description' => t('Enter the number of items to skip; enter 0 to skip no items.'),
  296. );
  297. }
  298. if ($allow['path_override']) {
  299. $form['path'] = array(
  300. '#type' => 'textfield',
  301. '#default_value' => isset($conf['path']) ? $conf['path'] : $view->get_path(),
  302. '#title' => t('Override path'),
  303. '#size' => 30,
  304. '#description' => t('If this is set, override the View URL path; this can sometimes be useful to set to the panel URL.'),
  305. );
  306. if (!empty($contexts)) {
  307. $form['path']['#description'] .= ' ' . t('You may use substitutions in this path.');
  308. $form['contexts'] = array(
  309. '#type' => 'fieldset',
  310. '#title' => t('Substitutions'),
  311. '#collapsible' => TRUE,
  312. '#collapsed' => TRUE,
  313. );
  314. $rows = array();
  315. foreach ($contexts as $context) {
  316. foreach (ctools_context_get_converters('%' . check_plain($context->keyword) . ':', $context) as $keyword => $title) {
  317. $rows[] = array(
  318. check_plain($keyword),
  319. t('@identifier: @title', array('@title' => $title, '@identifier' => $context->identifier)),
  320. );
  321. }
  322. }
  323. $header = array(t('Keyword'), t('Value'));
  324. $form['contexts']['context'] = array('#markup' => theme('table', array('header' => $header, 'rows' => $rows)));
  325. }
  326. }
  327. if (empty($conf['exposed'])) {
  328. $conf['exposed'] = array();
  329. }
  330. if ($allow['exposed_form']) {
  331. // If the exposed form is part of pane configuration, get the exposed
  332. // form re-tool it for our use.
  333. $exposed_form_state = array(
  334. 'view' => &$view,
  335. 'display' => &$view->display[$display_id],
  336. );
  337. $view->set_exposed_input($conf['exposed']);
  338. if (version_compare(views_api_version(), '3', '>=')) {
  339. $exposed_form_state['exposed_form_plugin'] = $view->display_handler->get_plugin('exposed_form');
  340. }
  341. $view->init_handlers();
  342. $exposed_form = array();
  343. $exposed_form = views_exposed_form($exposed_form, $exposed_form_state);
  344. $form['exposed'] = array(
  345. '#tree' => TRUE,
  346. );
  347. foreach ($exposed_form['#info'] as $id => $info) {
  348. $form['exposed'][$id] = array(
  349. '#type' => 'item',
  350. '#id' => 'views-exposed-pane',
  351. );
  352. if (!empty($info['label'])) {
  353. $form['exposed'][$id]['#title'] = $info['label'];
  354. }
  355. if (!empty($info['operator']) && !empty($exposed_form[$info['operator']])) {
  356. $form['exposed'][$id][$info['operator']] = $exposed_form[$info['operator']];
  357. $form['exposed'][$id][$info['operator']]['#parents'] = array('exposed', $info['operator']);
  358. $form['exposed'][$id][$info['operator']]['#default_value'] = isset($conf['exposed'][$info['operator']]) ? $conf['exposed'][$info['operator']] : '';
  359. }
  360. $form['exposed'][$id][$info['value']] = $exposed_form[$info['value']];
  361. $form['exposed'][$id][$info['value']]['#parents'] = array('exposed', $info['value']);
  362. $form['exposed'][$id][$info['value']]['#default_value'] = isset($conf['exposed'][$info['value']]) ? $conf['exposed'][$info['value']] : '';
  363. }
  364. }
  365. // The exposed sort stuff doesn't fall into $exposed_form['#info'] so we
  366. // have to handle it separately.
  367. if (isset($exposed_form['sort_by'])) {
  368. $form['exposed']['sort_by'] = $exposed_form['sort_by'];
  369. }
  370. if (isset($exposed_form['sort_order'])) {
  371. $form['exposed']['sort_order'] = $exposed_form['sort_order'];
  372. }
  373. // Add the view object to the form to allow additional customization
  374. $form_state['view'] = $view;
  375. return $form;
  376. }
  377. /**
  378. * Store form values in $conf.
  379. */
  380. function views_content_views_panes_content_type_edit_form_submit(&$form, &$form_state) {
  381. // Copy everything from our defaults.
  382. $keys = array('link_to_view', 'more_link', 'feed_icons', 'use_pager',
  383. 'pager_id', 'items_per_page', 'offset', 'path_override', 'path', 'arguments', 'fields_override', 'exposed');
  384. foreach ($keys as $key) {
  385. if (isset($form_state['values'][$key])) {
  386. $form_state['conf'][$key] = $form_state['values'][$key];
  387. }
  388. }
  389. }
  390. /**
  391. * Returns the administrative title for a type.
  392. */
  393. function views_content_views_panes_content_type_admin_title($subtype, $conf, $contexts) {
  394. list($name, $display) = explode('-', $subtype);
  395. $view = views_get_view($name);
  396. if (empty($view) || empty($view->display[$display])) {
  397. return t('Deleted/missing view @view', array('@view' => $name));
  398. }
  399. $view->set_display($display);
  400. views_content_views_panes_add_defaults($conf, $view);
  401. $title = views_content_get_display_title($view, $display);
  402. return check_plain($title);
  403. }
  404. /**
  405. * Returns the administrative title for a type.
  406. */
  407. function views_content_views_panes_content_type_admin_info($subtype, $conf, $contexts) {
  408. $info = array();
  409. list($view_name, $display_name) = explode('-', $subtype);
  410. $view = views_get_view($view_name);
  411. if (empty($view) || empty($view->display[$display_name])) {
  412. return;
  413. }
  414. $view->set_display($display_name);
  415. views_content_views_panes_add_defaults($conf, $view);
  416. // Add arguments first
  417. if (!empty($conf['arguments'])) {
  418. $keys = array_keys($conf['arguments']);
  419. $values = array_values($conf['arguments']);
  420. $argument_input = $view->display_handler->get_option('argument_input');
  421. foreach ($conf['arguments'] as $key => $value) {
  422. if (!empty($value)){
  423. $label = $argument_input[$key]['label'];
  424. $info[] = $label . ': ' . $value;
  425. }
  426. }
  427. }
  428. $block = new stdClass;
  429. if ($info) {
  430. $block->title = array_shift($info);
  431. $info[] = $view->display_handler->get_option('pane_description');
  432. $block->content = theme('item_list', array('items' => $info));
  433. }
  434. else {
  435. $block->title = $view->display_handler->get_option('pane_description');
  436. $block->content = '';
  437. }
  438. return $block;
  439. }