by douggreen: D6 menu system compliance.
[project/panels.git] / panels_views / panels_views.module
CommitLineData
ade117f2
EM
1<?php
2// $Id$
3
4/**
5 * @file panels_views.module
6 *
7 * Provides views as panels content, configurable by the administrator.
8 * Each view provided as panel content must be configured in advance,
9 * but once configured, building panels with views is a little bit simpler.
10 */
11
12/**
13 * Implementation of hook_menu().
14 */
15function panels_views_menu() {
16 $items = array();
17
18 $base = array(
19 'access arguments' => array('administer panel views'),
20 'file' => 'panels_views.admin.inc',
21 );
22
23 $items['admin/panels/views'] = array(
24 'title' => 'Views panes',
25 'type' => MENU_NORMAL_ITEM,
26 'page callback' => 'drupal_get_form',
27 'page arguments' => array('panels_views_admin_page'),
d8fff80a 28 'description' => 'Configure Views to be used as panes within panel displays.',
ade117f2
EM
29 ) + $base;
30
31 return $items;
32}
33
34/**
35 * Implementation of hook_panels_content_types()
36 */
37function panels_views_panels_content_types() {
38 // Only valid if views module loaded.
39 $items['views'] = array(
40 'title' => t('All views'),
41 'content_types' => 'panels_views_all_views_content_types',
42 'render callback' => 'panels_views_all_views_render',
43 'add callback' => 'panels_views_all_views_add',
44 'edit callback' => 'panels_views_all_views_edit',
45 'title callback' => 'panels_views_all_views_title',
46 );
d57d6d9d
EM
47 $items['views_panes'] = array(
48 'title' => t('All views'),
49 'content_types' => 'panels_views_panes_content_types',
50 'render callback' => 'panels_views_panes_render',
51 'add callback' => 'panels_views_panes_edit',
52 'edit callback' => 'panels_views_panes_edit',
53 'title callback' => 'panels_views_panes_title',
54 );
ade117f2
EM
55 return $items;
56}
57
58/**
d57d6d9d
EM
59 * Return all content types available.
60 */
61function panels_views_all_views_content_types() {
62 $types = array();
63
64 $views = views_get_all_views();
65
66 foreach ($views as $view) {
67 $view->init_display();
68
69 foreach ($view->display as $id => $display) {
70 $title = t('@name: @display', array('@name' => $view->name, '@display' => $display->display_title));
71
72 $icon = $display->display_plugin != 'page' ? 'icon_views_block_legacy.png' : 'icon_views_page_legacy.png';
73
74 $contexts = array();
75
76 if ($arguments = $display->handler->get_handlers('argument')) {
77 foreach ($arguments as $arg) {
78 $contexts[] = new panels_optional_context($arg->ui_name(), 'any');
79 }
80 }
81
82 $types[$view->name . '-' . $id] = array(
83 'title' => $title,
84 'icon' => $icon,
85 'description' => filter_xss_admin($view->description),
86 'required context' => $contexts,
87 'category' => array(t('Views'), -1),
88 );
89 }
90
91 }
92 return $types;
93}
94
95/**
ade117f2
EM
96 * Output function for the 'views' content type.
97 *
d57d6d9d 98 * Outputs a view based on the module and delta supplied in the configuration.
ade117f2 99 */
d57d6d9d 100function panels_views_all_views_render($subtype, $conf, $panel_args, $contexts) {
ade117f2
EM
101 if (!is_array($contexts)) {
102 $contexts = array($contexts);
103 }
104
d57d6d9d 105 list($name, $display) = explode('-', $subtype);
ade117f2
EM
106 $view = views_get_view($name);
107 if (empty($view)) {
108 return;
109 }
110
111 $view->set_display($display);
112 if (!$view->display_handler->access($GLOBALS['user'])) {
113 return;
114 }
115
116 $arguments = explode('/', $_GET['q']);
117 $args = $conf['args'];
118
119 foreach ($arguments as $id => $arg) {
120 $args = str_replace("%$id", $arg, $args);
121 }
122
123 foreach ($panel_args as $id => $arg) {
124 $args = str_replace("@$id", $arg, $args);
125 }
126
127 $args = preg_replace(',/?(%\d|@\d),', '', $args);
128 $args = $args ? explode('/', $args) : array();
129
130 if ($conf['panel_args'] && is_array($panel_args)) {
131 $args = array_merge($panel_args, $args);
132 }
133
134 if (is_array($conf['context'])) {
135 foreach ($conf['context'] as $count => $cid) {
136 if ($cid != 'any' && !empty($contexts[$count]) && isset($contexts[$count]->argument)) {
137 array_splice($args, $count, 0, array($contexts[$count]->argument));
138 }
139 }
140 }
141
142 $view->set_arguments($args);
143
144 if ($conf['url']) {
145 $view->display_handler->set_option('path', $conf['url']);
146 }
147
148 $block = new stdClass();
149 $block->module = 'views';
150 $block->delta = $view->name . $display;
151 $block->subject = $view->get_title();
152
153 if (!empty($conf['link_to_view'])) {
154 $block->title_link = $view->get_url();
155 }
156
157 if (!empty($conf['more_link'])) {
158 $block->more = array('href' => $view->get_url());
159 $view->display_handler->set_option('use_more', FALSE);
160 }
161 $view->display_handler->set_option('use_pager', $conf['use_pager']);
162 $view->display_handler->set_option('pager_element', $conf['pager_id']);
163 $view->display_handler->set_option('items_per_page', $conf['nodes_per_page']);
164 $view->display_handler->set_option('offset', $conf['offset']);
165
166 $stored_feeds = drupal_add_feed();
167 $block->content = $view->preview();
168
169 if (!empty($conf['feed_icons'])) {
170 $new_feeds = drupal_add_feed();
171 if ($diff = array_diff(array_keys($new_feeds), array_keys($stored_feeds))) {
172 foreach ($diff as $url) {
173 $block->feeds[$url] = $new_feeds[$url];
174 }
175 }
176 }
177
178 return $block;
179}
180
181/**
ade117f2
EM
182 * Returns the form for a new view.
183 */
184function panels_views_all_views_add($id, $parents, $conf = array()) {
d57d6d9d 185 list($name, $display_id) = explode('-', $id);
ade117f2
EM
186 $view = views_get_view($name);
187 if (!$view) {
188 return;
189 }
190 $view->set_display($display_id);
191
ade117f2
EM
192 $conf['nodes_per_page'] = $view->display_handler->get_option('items_per_page');
193 $conf['pager_id'] = 1;
194 $conf['use_pager'] = 0;
195 $conf['more_link'] = 0;
196 $conf['feed_icons'] = 0;
197 $conf['offset'] = 0;
198 $conf['panel_args'] = FALSE;
199 $conf['link_to_view'] = FALSE;
200 $conf['args'] = '';
201 $conf['url'] = '';
202 return panels_views_all_views_edit($id, $parents, $conf);
203}
204
205/**
206 * Returns an edit form for a block.
207 */
208function panels_views_all_views_edit($id, $parents, $conf) {
ade117f2
EM
209 $form['link_to_view'] = array(
210 '#type' => 'checkbox',
211 '#default_value' => $conf['link_to_view'],
212 '#title' => t('Link title to view'),
213 '#description' => t('If checked, the title will be a link to the view.'),
214 );
215
216 $form['more_link'] = array(
217 '#type' => 'checkbox',
218 '#default_value' => $conf['more_link'],
219 '#title' => t('Provide a "more" link that links to the view'),
220 '#description' => t('This is independent of any more link that may be provided by the view itself; if you see two more links, turn this one off. Views will only provide a more link if using the "block" type, however, so if using embed, use this one.'),
221 );
222
223 $form['feed_icons'] = array(
224 '#type' => 'checkbox',
225 '#default_value' => $conf['feed_icons'],
226 '#title' => t('Display feed icons'),
227 '#description' => t('If checked, any feed icons provided by this view will be displayed.'),
228 );
229
230 $form['pager_aligner_start'] = array(
231 '#value' => '<div class="option-text-aligner">',
232 );
233 $form['use_pager'] = array(
234 '#type' => 'checkbox',
235 '#title' => t('Use pager'),
236 '#default_value' => $conf['use_pager'],
237 '#id' => 'use-pager-checkbox',
238 );
239 $form['pager_id'] = array(
240 '#type' => 'textfield',
241 '#default_value' => $conf['pager_id'],
242 '#title' => t('Pager ID'),
243 '#size' => 4,
244 '#id' => 'use-pager-textfield',
245 );
246 $form['pager_aligner_stop'] = array(
247 '#value' => '</div><div style="clear: both; padding: 0; margin: 0"></div>',
248 );
249
250 $form['nodes_per_page'] = array(
251 '#type' => 'textfield',
252 '#default_value' => $conf['nodes_per_page'],
253 '#title' => t('Num posts'),
254 '#size' => 4,
255 '#description' => t('Select the number of posts to display, or 0 to display all results.'),
256 );
257
258 $form['offset'] = array(
259 '#type' => 'textfield',
260 '#default_value' => $conf['offset'],
261 '#title' => t('Offset'),
262 '#size' => 4,
263 '#description' => t('Offset in the node list or 0 to start at 1st item.'),
264 );
265
266 $form['panel_args'] = array(
267 '#type' => 'checkbox',
268 '#title' => t('Send arguments'),
269 '#default_value' => $conf['panel_args'],
270 '#description' => t('Select this to send all arguments from the panel directly to the view. If checked, the panel arguments will come after any context arguments above and precede any additional arguments passed in through the Arguments field below.'),
271 );
272
273 $form['args'] = array(
274 '#type' => 'textfield',
275 '#default_value' => $conf['args'],
276 '#title' => t('Arguments'),
277 '#size' => 30,
278 '#description' => t('Additional arguments to send to the view as if they were part of the URL in the form of arg1/arg2/arg3. You may use %0, %1, ..., %N to grab arguments from the URL. Or use @0, @1, @2, ..., @N to use arguments passed into the panel.'),
279 );
280
281 $form['url'] = array(
282 '#type' => 'textfield',
283 '#default_value' => $conf['url'],
284 '#title' => t('Override URL'),
285 '#size' => 30,
286 '#description' => t('If this is set, override the View URL; this can sometimes be useful to set to the panel URL'),
287 );
288
289 return $form;
290}
291
292/**
293 * Returns the administrative title for a type.
294 */
d57d6d9d
EM
295function panels_views_all_views_title($subtype, $conf) {
296 list($name, $display) = explode('-', $subtype);
ade117f2
EM
297 $view = views_get_view($name);
298 if (empty($view)) {
d57d6d9d 299 return t('Deleted/missing view @view', array('@view' => $name));
ade117f2
EM
300 }
301 if (empty($view->display[$display])) {
d57d6d9d 302 return t('Deleted/missing view @view', array('@view' => $name));
ade117f2
EM
303 }
304 return t('@name: @display', array('@name' => $view->name, '@display' => $view->display[$display]->display_title));
305}
306
d57d6d9d 307
ade117f2
EM
308/**
309 * Don't show Views' blocks; we expose them already.
310 */
311function views_panels_block_info($module, $delta, &$info) {
312 $info = NULL;
313}
d57d6d9d
EM
314
315// --------------------------------------------------------------------------
316// Panels functions for the panel pane display plugin.
317
318/**
319 * Return all views that have panel pane displays on them.
320 */
321
322function panels_views_panes_content_types() {
323 $types = array();
324
325 $views = views_get_all_views();
326
327 foreach ($views as $view) {
328 $view->init_display();
329
330 foreach ($view->display as $id => $display) {
331 if (empty($display->handler->panel_pane_display)) {
332 continue;
333 }
334
335 $title = $display->handler->get_option('pane_title');
336 if (!$title) {
337 $title = $view->name;
338 }
339
340 $description = $display->handler->get_option('pane_description');
341 if (!$description) {
342 $description = $view->description;
343 }
344
345 $category = $display->handler->get_option('pane_category');
346 if (!$category['name']) {
347 $category['name'] = t('View panes');
348 }
349
350 $icon = 'icon_views_page.png';
351
352 $contexts = array();
353
354 $arguments = $display->handler->get_argument_input();
355 foreach ($arguments as $argument) {
356 if ($argument['type'] == 'context') {
357 $contexts[] = new panels_required_context($argument['label'], $argument['context']);
358 }
359 }
360
361 $types[$view->name . '-' . $id] = array(
362 'title' => $title,
363 'icon' => $icon,
364 'description' => filter_xss_admin($description),
365 'required context' => $contexts,
366 'category' => array($category['name'], $category['weight']),
367 );
368 }
369 }
370
371 return $types;
372}
373
374/**
375 * Render a view pane
376 */
377function panels_views_panes_render($subtype, $conf, $panel_args, $contexts) {
378 if (!is_array($contexts)) {
379 $contexts = array($contexts);
380 }
381
382 list($name, $display) = explode('-', $subtype);
383 $view = views_get_view($name);
384 if (empty($view)) {
385 return;
386 }
387
388 $view->set_display($display);
389 if (!$view->display_handler->access($GLOBALS['user'])) {
390 return;
391 }
392
393 if (!$view->display_handler->access($GLOBALS['user'])) {
394 return;
395 }
396
397 $args = array();
398 $arguments = $view->display_handler->get_option('arguments');
399
400 foreach ($view->display_handler->get_argument_input() as $id => $argument) {
401 switch ($argument['type']) {
402 case 'context':
403 $c = array_shift($contexts);
404 $args[] = $c->argument;
405 break;
406
407 case 'fixed':
408 $args[] = $argument['fixed'];
409 break;
410
411 case 'panel':
412 $args[] = $panel_args[$argument['panel']];
413 break;
414
415 case 'user':
416 $args[] = isset($conf['arguments'][$id]) ? $conf['arguments'][$id] : NULL;
417 break;
418
419 case 'wildcard':
420 // Put in the wildcard.
421 $args[] = isset($arguments[$id]['wildcard']) ? $arguments[$id]['wildcard'] : '*';
422 break;
423
424 case 'none':
425 default:
426 // Put in NULL.
427 // views.module knows what to do with NULL (or missing) arguments
428 $args[] = NULL;
429 break;
430 }
431 }
432
433 // remove any trailing NULL arguments as these are non-args:
434 while (count($args) && end($args) === NULL) {
435 array_pop($args);
436 }
437 $view->set_arguments($args);
438
439 if ($allow['path_override'] && !empty($conf['path'])) {
440 $view->display_handler->set_option('path', $conf['path']);
441 }
442
443 $block = new stdClass();
444 $block->module = 'views';
445 $block->delta = $view->name . $display;
446 $block->subject = $view->get_title();
447
448 if (($allow['link_to_view'] && !empty($conf['link_to_view'])) ||
449 (!$allow['link_to_view'] && $view->display_handler->get_option['link_to_view'])) {
450 $block->title_link = $view->get_url();
451 }
452
453 // more link
454 if (($allow['more_link'] && !empty($conf['more_link'])) ||
455 (!$allow['more_link'] && $view->display_handler->get_option['more_link'])) {
456 $block->more = array('href' => $view->get_url());
457 $view->display_handler->set_option('use_more', FALSE);
458 // make sure the view runs the count query so we know whether or not the more link
459 // applies.
460 $view->get_total_rows = TRUE;
461 }
462
463 if ($allow['use_pager']) {
464 $view->display_handler->set_option('use_pager', $conf['use_pager']);
465 $view->display_handler->set_option('pager_element', $conf['pager_id']);
466 }
467 if ($allow['items_per_page']) {
468 $view->display_handler->set_option('items_per_page', $conf['items_per_page']);
469 }
470 if ($allow['offset']) {
471 $view->display_handler->set_option('offset', $conf['offset']);
472 }
473
474 $stored_feeds = drupal_add_feed();
475
476 $block->content = $view->preview();
477
478 if ($view->total_rows <= $view->display_handler->get_option('items_per_page')) {
479 unset($block->more);
480 }
481
482 if (($allow['feed_icons'] && !empty($conf['feed_icons'])) ||
483 (!$allow['feed_icons'] && $view->display_handler->get_option['feed_icons'])) {
484 $new_feeds = drupal_add_feed();
485 if ($diff = array_diff(array_keys($new_feeds), array_keys($stored_feeds))) {
486 foreach ($diff as $url) {
487 $block->feeds[$url] = $new_feeds[$url];
488 }
489 }
490 }
491
492 return $block;
493}
494
495function panels_views_panes_edit($id, $parents, $conf) {
496 list($name, $display_id) = explode('-', $id);
497 $view = views_get_view($name);
498 if (!$view) {
499 return;
500 }
501 $view->set_display($display_id);
502
503 $allow = $view->display_handler->get_option('allow');
504
505 // Provide defaults for everything in order to prevent warnings.
506 if (empty($conf)) {
507 $conf['link_to_view'] = $view->display_handler->get_option('link_to_view');
508 $conf['more_link'] = $view->display_handler->get_option('more_link');
509 $conf['feed_icons'] = $pv->feed_icons;
510 $conf['use_pager'] = $view->display_handler->get_option('use_pager');
511 $conf['element_id'] = $view->display_handler->get_option('element_id');
512 $conf['items_per_page'] = $view->display_handler->get_option('items_per_page');
513 $conf['offset'] = $view->display_handler->get_option('offset');
514 $conf['path_override'] = FALSE;
515 $conf['url'] = $view->get_path();
516 }
517
518 foreach ($view->display_handler->get_argument_input() as $id => $argument) {
519 if ($argument['type'] == 'user') {
520 $form['arguments'][$id] = array(
521 '#type' => 'textfield',
522 '#default_value' => isset($conf['arguments'][$id]) ? $conf['arguments'][$id] : '',
523 '#title' => $argument['label'],
524 );
525 }
526 }
527 if ($view->display_handler->has_path()) {
528 if ($allow['link_to_view'] ) {
529 $form['link_to_view'] = array(
530 '#type' => 'checkbox',
531 '#default_value' => $conf['link_to_view'],
532 '#title' => t('Link title to page'),
533 '#description' => t('If checked, the title will be a link to the page.'),
534 );
535 }
536 if ($allow['more_link']) {
537 $form['more_link'] = array(
538 '#type' => 'checkbox',
539 '#default_value' => $conf['more_link'],
540 '#title' => t('Provide a "more" link that links to the view'),
541 '#description' => t('This is independent of any more link that may be provided by the view itself; if you see two more links, turn this one off. Views will only provide a more link if using the "block" type, however, so if using embed, use this one.'),
542 );
543 }
544 }
545
546 if ($allow['feed_icons']) {
547 $form['feed_icons'] = array(
548 '#type' => 'checkbox',
549 '#default_value' => $conf['feed_icons'],
550 '#title' => t('Display feed icons'),
551 '#description' => t('If checked, any feed icons provided will be displayed.'),
552 );
553 }
554
555 if ($allow['use_pager']) {
556 $form['pager_aligner_start'] = array(
557 '#value' => '<div class="option-text-aligner">',
558 );
559 $form['use_pager'] = array(
560 '#type' => 'checkbox',
561 '#title' => t('Use pager'),
562 '#default_value' => $conf['use_pager'],
563 '#id' => 'use-pager-checkbox',
564 );
565 $form['pager_id'] = array(
566 '#type' => 'textfield',
567 '#default_value' => $conf['pager_id'],
568 '#title' => t('Pager ID'),
569 '#size' => 4,
570 '#id' => 'use-pager-textfield',
571 );
572 $form['pager_aligner_stop'] = array(
573 '#value' => '</div><div style="clear: both; padding: 0; margin: 0"></div>',
574 );
575 }
576 if ($allow['items_per_page']) {
577 $form['items_per_page'] = array(
578 '#type' => 'textfield',
579 '#default_value' => $conf['items_per_page'],
580 '#title' => t('Num items'),
581 '#size' => 4,
582 '#description' => t('Select the number of items to display, or 0 to display all results.'),
583 );
584 }
585 if ($allow['offset']) {
586 $form['offset'] = array(
587 '#type' => 'textfield',
588 '#default_value' => $conf['offset'],
589 '#title' => t('Offset'),
590 '#size' => 4,
591 '#description' => t('Enter the number of items to skip; enter 0 to skip no items.'),
592 );
593 }
594 if ($allow['path_override']) {
595 // TODO: Because javascript in the dialogs is kind of weird, dependent checkboxes
596 // don't work right for external modules. This needs fixing in panels itself.
597 $form['path'] = array(
598 '#type' => 'textfield',
599 '#default_value' => $conf['path'],
600 '#title' => t('Override path'),
601 '#size' => 30,
602 '#description' => t('If this is set, override the View URL path; this can sometimes be useful to set to the panel URL.'),
603 );
604 }
605
606 return $form;
607}
608
609function panels_views_panes_title($subtype, $conf) {
610 list($name, $display) = explode('-', $subtype);
611 $view = views_get_view($name);
612 if (empty($view)) {
613 return t('Deleted/missing view @view', array('@view' => $name));
614 }
615 if (empty($view->display[$display])) {
616 return t('Deleted/missing view @view', array('@view' => $name));
617 }
618
619 $view->set_display($display);
620 $title = $view->display_handler->get_option('pane_title');
621 return check_plain($title ? $title : $view->name);
622}