Stripping CVS keywords
[project/panels.git] / panels.module
1 <?php
2
3 /**
4 * Implementation of hook_help()
5 */
6 function panels_help($section = '') {
7 switch ($section) {
8 case 'admin/modules#description':
9 return t('The panels module allows the creation of pages with flexible layouts.');
10 case 'admin/panels':
11 case 'admin/panels/list':
12 return t('<p>You may peruse a list of your current panels layouts and edit them, or click add to create a new page.</p>');
13 case 'admin/panels/add':
14 return t('<p>Choose a layout for your new page from the list below.</p>');
15 }
16 }
17
18 /**
19 * Implementation of hook_perm()
20 */
21 function panels_perm() {
22 return array('create panels', 'access all panels');
23 }
24
25 /**
26 * Determine if the specified user has access to a panel.
27 */
28 function panels_access($panel, $account = NULL) {
29 if (!$account) {
30 global $user;
31 $account = $user;
32 }
33
34 // Administrator privileges
35 if (user_access('access all panels', $account)) {
36 return TRUE;
37 }
38
39 // All views with an empty access setting are available to all roles.
40 if (!$panel->access) {
41 return TRUE;
42 }
43
44 // Otherwise, check roles
45 static $roles = array();
46 if (!isset($roles[$account->uid])) {
47 $roles[$account->uid] = array_keys($account->roles);
48 }
49
50 return array_intersect($panel->access, $roles[$account->uid]);
51 }
52
53 /**
54 * Implementation of hook_menu()
55 */
56 function panels_menu($may_cache) {
57 if ($may_cache) {
58 $access = user_access('create panels');
59 $items[] = array(
60 'path' => 'admin/panels',
61 'title' => t('panels'),
62 'access' => $access,
63 'callback' => 'panels_list_page',
64 );
65 $items[] = array(
66 'path' => 'admin/panels/list',
67 'title' => t('list'),
68 'access' => $access,
69 'callback' => 'panels_list_page',
70 'weight' => -10,
71 'type' => MENU_DEFAULT_LOCAL_TASK,
72 );
73 $items[] = array(
74 'path' => 'admin/panels/add',
75 'title' => t('add'),
76 'access' => $access,
77 'callback' => 'panels_add_page',
78 'type' => MENU_LOCAL_TASK,
79 );
80 $items[] = array(
81 'path' => 'admin/panels/add/layout',
82 'title' => t('add'),
83 'access' => $access,
84 'callback' => 'panels_add_layout_page',
85 'type' => MENU_LOCAL_TASK,
86 );
87 $items[] = array(
88 'path' => 'admin/panels/edit',
89 'title' => t('edit panels'),
90 'access' => $access,
91 'callback' => 'panels_edit_page',
92 'type' => MENU_CALLBACK,
93 );
94 $items[] = array(
95 'path' => 'admin/panels/delete',
96 'title' => t('delete panels'),
97 'access' => $access,
98 'callback' => 'panels_delete_page',
99 'type' => MENU_CALLBACK,
100 );
101
102 $items[] = array(
103 'path' => 'panels/node/autocomplete',
104 'title' => t('autocomplete node'),
105 'callback' => 'panels_node_autocomplete',
106 'access' => user_access('access content'),
107 'type' => MENU_CALLBACK
108 );
109
110 // load panels from database
111 $result = db_query("SELECT * FROM {panels_info}");
112 // FIXME: Fow now we're making these all callbacks, but we
113 // should steal code from Views so they can be normal, tabs,
114 // etc
115 while ($panels = db_fetch_object($result)) {
116 $panels->access = ($panels->access ? explode(', ', $panels->access) : array());
117 $items[] = array(
118 'path' => $panels->path,
119 'title' => filter_xss_admin($panels->title),
120 'access' => panels_access($panels),
121 'callback' => 'panels_panels_page',
122 'callback arguments' => array($panels->did),
123 'type' => MENU_CALLBACK
124 );
125 }
126 }
127 return $items;
128 }
129
130 /**
131 * panels path helper function
132 */
133 function panels_get_file_path($module, $file, $base_path = true) {
134 if ($base_path) {
135 $output = base_path();
136 }
137 return $output . drupal_get_path('module', $module) . '/' . $file;
138 }
139
140 // ---------------------------------------------------------------------------
141 // panels custom image button
142
143 /**
144 * Custom form element to do our nice images.
145 */
146 function panels_elements() {
147 $type['panels_imagebutton'] = array('#input' => TRUE, '#button_type' => 'submit',);
148 return $type;
149 }
150
151 /**
152 * Theme our image button.
153 */
154 function theme_panels_imagebutton($element) {
155 return '<input type="image" class="form-'. $element['#button_type'] .'" name="'. $element['#name'] .'" value="'. check_plain($element['#default_value']) .'" '. drupal_attributes($element['#attributes']) . ' src="' . $element['#image'] . '" alt="' . $element['#title'] . '" title="' . $element['#title'] . "\" />\n";
156 }
157
158 function panels_imagebutton_value() {
159 // null function guarantees default_value doesn't get moved to #value.
160 }
161
162 /**
163 * Add a single button to a form.
164 */
165 function panels_add_button($image, $name, $text) {
166 $module_path = base_path() . drupal_get_path('module', 'panels');
167
168 return array(
169 '#type' => 'panels_imagebutton',
170 '#image' => $module_path . '/images/' . $image,
171 '#title' => $text,
172 '#default_value' => $name,
173 );
174 }
175
176 /**
177 * Set a button to a blank image -- used for placeholders when buttons are
178 * not relevant but just removing it would be visually unappealing.
179 */
180 function panels_set_blank(&$form) {
181 $form['#type'] = 'markup';
182 $form['#value'] = theme('image', drupal_get_path('module', 'panels') . '/images/blank.gif');
183 }
184
185 // ---------------------------------------------------------------------------
186 // panels administrative pages
187
188 /**
189 * Provide a list of panels, with links to edit or delete them.
190 */
191 function panels_list_page() {
192 $result = db_query("SELECT * FROM {panels_info} ORDER BY title");
193 while ($panels = db_fetch_object($result)) {
194 $item = array();
195 $item[] = check_plain($panels->title);
196 $item[] = l($panels->path, $panels->path);
197 $item[] = implode(' | ', array(
198 l('edit', "admin/panels/edit/$panels->did"),
199 l('delete', "admin/panels/delete/$panels->did"),
200 ));
201 $items[] = $item;
202 }
203 $header = array(
204 t('Panel title'),
205 t('URL'),
206 t('Operations'),
207 );
208 $output = theme('table', $header, $items);
209 return $output;
210 }
211
212 /*
213 * Provide a form to confirm deletion of a panel page.
214 */
215 function panels_delete_page($did = '') {
216 $panels = panels_load_panels($did);
217
218 if (!$panels) {
219 return 'admin/panels';
220 }
221
222 $form['did'] = array('#type' => 'value', '#value' => $panels->did);
223 return confirm_form('panels_delete_confirm', $form,
224 t('Are you sure you want to delete %title?', array('%title' => $panels->title)),
225 $_GET['destination'] ? $_GET['destination'] : 'admin/panels',
226 t('This action cannot be undone.'),
227 t('Delete'), t('Cancel')
228 );
229 }
230
231 /*
232 * Handle the submit button to delete a panel page.
233 */
234 function panels_delete_confirm_submit($formid, $form) {
235 if ($form['confirm']) {
236 panels_delete_panels((object) $form);
237 return 'admin/panels';
238 }
239 }
240
241 /**
242 * Handle the add panels page
243 */
244 function panels_add_page($layout = NULL) {
245 $layouts = panels_get_layouts();
246 theme_add_style(drupal_get_path('module', 'panels') . '/panels_admin.css');
247 if (!$layout) {
248 foreach ($layouts as $id => $layout) {
249 if (!$default_id) {
250 // grab the first one for our default.
251 $default_id = $id;
252 }
253 $file = panels_get_file_path($layout['module'], $layout['icon'], false);
254 $output .= theme('panels_add_image', $layout[title], $id, l(theme('image', $file), $_GET['q'] . '/' . $id, NULL, NULL, NULL, NULL, TRUE));
255 }
256 return $output;
257 }
258
259 if (!$layouts[$layout]) {
260 return drupal_not_found();
261 }
262
263 $panels->layout = $layout;
264 return panels_edit_form($panels);
265 }
266
267 function theme_panels_add_image($title, $id, $image) {
268 $output .= '<div class="layout-link">';
269 $output .= $image;
270 $output .= '<div>' . l($title, $_GET['q'] . '/' . $id) . '</div>';
271 $output .= '</div>';
272 return $output;
273 }
274 // ---------------------------------------------------------------------------
275 // panels administrative pages
276
277 function panels_edit_page($did = NULL) {
278 if (!$did || !($panels = panels_load_panels($did))) {
279 return drupal_not_found();
280 }
281 return panels_edit_form($panels);
282 }
283
284 /**
285 * shortcut to ease the syntax of the various form builder tricks we use.
286 */
287 function panels_form_builder(&$form, $form_id = 'panels_edit_form') {
288 $form = form_builder($form_id, $form);
289 }
290
291 /**
292 * Edit an already loaded panels.
293 */
294 function panels_edit_form($panels) {
295 theme_add_style(drupal_get_path('module', 'panels') . '/panels_admin.css');
296 $layouts = panels_get_layouts();
297 $layout = $layouts[$panels->layout];
298
299 $content_types = panels_get_content_types();
300
301 // Process all our add button stuff first so we can add stuff to the
302 // form semi dynamically.
303
304 $form['add'] = array(
305 '#type' => 'fieldset',
306 '#title' => t('Add content'),
307 '#collapsible' => false,
308 '#description' => t('Select an area to add content to, then select a type of content and click the appropriate button. The content will be added.'),
309 );
310
311 // Drop the array keys into a temporary in order to protect references.
312 $temp = array_keys($layout['content areas']);
313 $default_radio = array_shift($temp);
314
315 $form['add']['area'] = array(
316 '#type' => 'radios',
317 '#title' => t('Area'),
318 '#options' => $layout['content areas'],
319 '#prefix' => '<div class="container-inline">',
320 '#suffix' => '</div>',
321 '#default_value' => $default_radio,
322 );
323 foreach ($content_types as $id => $type) {
324 $function = $type['admin'];
325 if (function_exists($function)) {
326 global $form_values;
327 $form['add'][$id] = $function('add button', $dummy);
328
329 // $dummy needed for cause you can't have default args on a reference.
330 $form['add'][$id]['#parents'] = array('add', $id);
331 $form['add'][$id]['#tree'] = true;
332 panels_form_builder($form['add'][$id]);
333
334 if ($conf = $function('add', $form_values['add'][$id])) {
335 $add->configuration = $conf;
336 $add->type = $id;
337 $form['add']['area']['#parents'] = array('area');
338 panels_form_builder($form['add']['area']);
339 $add->area = $form_values['area'];
340 }
341 }
342 }
343
344 $form['layout'] = array(
345 '#type' => 'value',
346 '#value' => $panels->layout
347 );
348
349 $form['did'] = array(
350 '#type' => 'value',
351 '#value' => $panels->did,
352 );
353
354 $form['info'] = array(
355 '#type' => 'fieldset',
356 '#title' => t('General information'),
357 '#collapsible' => false,
358 );
359
360 $file = panels_get_file_path($layout['module'], $layout['icon'], false);
361 $icon .= theme('image', $file);
362 $form['info']['layout-icon'] = array(
363 '#value' => '<div class="layout-icon">' . $icon . '</div>',
364 );
365
366 $form['info']['layout-display'] = array(
367 '#value' => '<strong>Layout</strong>: ' . $layout['title'],
368 );
369
370 $form['info']['title'] = array(
371 '#type' => 'textfield',
372 '#default_value' => $panels->title,
373 '#title' => t('Page title'),
374 '#description' => t('The page title for this panels layout'),
375 );
376
377 $form['info']['css_id'] = array(
378 '#type' => 'textfield',
379 '#default_value' => $panels->css_id,
380 '#title' => t('CSS ID'),
381 '#description' => t('The CSS ID to apply to this page'),
382 );
383
384 $rids = array();
385 $result = db_query("SELECT r.rid, r.name FROM {role} r ORDER BY r.name");
386 while ($obj = db_fetch_object($result)) {
387 $rids[$obj->rid] = $obj->name;
388 }
389
390 $form['info']['access'] = array(
391 '#type' => 'checkboxes',
392 '#title' => t('Access'),
393 '#default_value' => $panels->access,
394 '#options' => $rids,
395 '#description' => t('Only the checked roles will be able to see this panel in any form; if no roles are checked, access will not be restricted.'),
396 );
397
398 $form['info']['path'] = array(
399 '#type' => 'textfield',
400 '#default_value' => $panels->path,
401 '#title' => t('Path'),
402 '#description' => t('The URL path to give this page, i.e, path/to/page'),
403 '#required' => TRUE,
404 );
405
406 $form['content'] = array(
407 '#tree' => true,
408 );
409
410 // Go through our content areas and display what we have.
411 foreach ($layout['content areas'] as $area => $title) {
412 $list = array();
413 $form['content'][$area] = array(
414 '#tree' => true,
415 );
416
417 // Construct the order, feeding it the default order for what
418 // we know about. When we pull it back out, it may well be
419 // different due to past submits.
420 $order = array();
421 if (is_array($panels->content[$area])) {
422 $order = array_keys($panels->content[$area]);
423 }
424 $form['content'][$area]['order'] = array(
425 '#type' => 'hidden',
426 '#default_value' => serialize($order),
427 '#parents' => array('content', $area, 'order'),
428 );
429
430 // If an add button has added an item to the area, put it in and update
431 // the $order.
432 panels_form_builder($form['content'][$area]['order']);
433 $order = unserialize($form['content'][$area]['order']['#value']);
434 if ($add->area == $area) {
435 // say THIS 5 times real fast
436 if ($panels->content[$area] && $order) {
437 $position = max(max(array_keys($order)), max(array_keys($panels->content[$area]))) + 1;
438 }
439 else if ($order) {
440 $position = max(array_keys($order)) + 1;
441 }
442 else {
443 $position = 0;
444 }
445
446 $panels->content[$area][$position] = $add;
447 $order[] = $position;
448 $form['content'][$area]['order']['#value'] = serialize($order);
449 }
450
451 // Go through each item in the area and render it.
452 $count = count($order);
453 foreach ($order as $position => $id) {
454 // place buttons to re-order content.
455 $form['content'][$area][$id]['buttons'] = array(
456 '#parents' => array('content', $area, $id, 'buttons'),
457 '#tree' => TRUE
458 );
459 panels_add_buttons($form['content'][$area][$id]['buttons'], $count, $position);
460
461 // figure out if one of those buttons was pressed
462 panels_form_builder($form['content'][$area][$id]['buttons']);
463 $deleted = false;
464 foreach ($GLOBALS['form_values']['content'][$area][$id]['buttons'] as $button => $value) {
465 if ($value) {
466 $function = 'panels_move_' . $button;
467 $function($order, $position);
468 $form['content'][$area]['order']['#value'] = serialize($order);
469 if ($button == 'delete')
470 $deleted = true;
471 }
472 }
473 // If a content item was deleted, it still has buttons. Get rid of them.
474 // It had buttons because we needed to give it buttons to see if its
475 // buttons were clicked.
476 if ($deleted) {
477 unset($form['content'][$area][$id]['buttons']);
478 }
479 else {
480 // we finally get to add the conent item's content to the form.
481 $area_record = $panels->content[$area][$id];
482 $form['content'][$area][$id]['type'] = array(
483 '#type' => 'hidden',
484 '#default_value' => $area_record->type,
485 '#parents' => array('content', $area, $id, 'type'),
486 );
487 // retrieve what was already there -- so we can retain edits and
488 // content items that were added.
489 panels_form_builder($form['content'][$area][$id]['type']);
490 $type = $form['content'][$area][$id]['type']['#value'];
491 $function = $content_types[$type]['admin'];
492 if (function_exists($function)) {
493 $array = array(
494 '#tree' => true,
495 '#parents' => array('content', $area, $id, 'configuration'),
496 );
497 $form['content'][$area][$id]['configuration'] = array_merge($array, $function('edit', $area_record->configuration, array('content', $area, $id, 'configuration')));
498 panels_form_builder($form['content'][$area][$id]['configuration']);
499 }
500 }
501 }
502 }
503
504 $form['submit'] = array(
505 '#type' => 'submit',
506 '#value' => t('Save'),
507 );
508
509 return drupal_get_form('panels_edit_form', $form);
510 }
511
512 /**
513 * Display the form to edit a panels.
514 */
515 function theme_panels_edit_form($form) {
516 $layouts = panels_get_layouts();
517 $layout = $layouts[$form['layout']['#value']];
518
519 $content_types = panels_get_content_types();
520
521 $output .= form_render($form['info']);
522 foreach ($layout['content areas'] as $area => $title) {
523 $order = unserialize($form['content'][$area]['order']['#value']);
524 if (!$order) {
525 $area_content = t('This area has no content.');
526 }
527 else {
528 $area_content = '';
529 $count = count($order);
530 foreach ($order as $position => $id) {
531 if ($count > 1) {
532 if ($position == 0 ) {
533 panels_set_blank($form['content'][$area][$id]['buttons']['up']);
534 }
535 else if ($position == ($count - 1)) {
536 panels_set_blank($form['content'][$area][$id]['buttons']['down']);
537 }
538 }
539 $type = $form['content'][$area][$id]['type']['#value'];
540 $function = $content_types[$type]['admin'];
541 if (function_exists($function)) {
542 // figure out the actual values; using the global because we need it
543 // to be in the same format it'll be in 'submit'.
544 global $form_values;
545 $conf_form = $form_values['content'][$area][$id]['configuration'];
546 $conf = $function('save', $conf_form);
547 $fieldset = array(
548 '#title' => t('Configure'),
549 '#children' => form_render($form['content'][$area][$id]['configuration']),
550 '#collapsible' => true,
551 '#collapsed' => true
552 );
553 $buttons = form_render($form['content'][$area][$id]['buttons']);
554 $area_content .= $buttons . '&nbsp;' . $function('list', $conf) .
555 theme('fieldset', $fieldset) /* . '<br />' */;
556 }
557 }
558 }
559 $content[$area] = theme('fieldset', array('#title' => check_plain($title), '#value' => $area_content));
560 }
561
562 $output .= panels_get_layout($layout, $content);
563
564 $output .= form_render($form);
565 return $output;
566 }
567
568 function panels_edit_form_validate($form_id, $form_values, $form) {
569 $content_types = panels_get_content_types();
570 foreach ($form_values['content'] as $area => $content) {
571 foreach ($content as $id => $item) {
572 if (is_numeric($id)) {
573 $function = $content_types[$item['type']]['admin'];
574 if (function_exists($function)) {
575 $function('validate', $item['configuration'], $form['content'][$area][$id]['configuration']);
576 }
577 }
578 }
579 }
580 }
581
582 function panels_edit_form_submit($form_id, $form_values) {
583 $panels = (object) $form_values;
584 // be sure we get the order right.
585 foreach ($form_values['content'] as $area => $content) {
586 $array = array();
587 $order = unserialize($content['order']);
588 if (is_array($order)) {
589 foreach($order as $id) {
590 $array[] = $content[$id];
591 }
592 }
593 $panels->content[$area] = $array;
594 }
595 $panels->access = array_keys(array_filter($panels->access));
596 panels_save_panels($panels);
597 drupal_set_message(t('The panels has been saved.'));
598 return 'admin/panels';
599 }
600
601 /**
602 * add the buttons to a content item
603 */
604 function panels_add_buttons(&$form, $count, $position) {
605 $form['delete'] = panels_add_button('user-trash.png', 'delete', t('Delete this item'));
606 // Leaving these in but commented out as I'm not convinced we don't want them.
607 // if ($count > 2) {
608 // $form['top'] = panels_add_button('go-top.png', 'top', t('Move item to top'));
609 // }
610 if ($count > 1) {
611 $form['up'] = panels_add_button('go-up.png', 'up', t('Move item up'));
612 $form['down'] = panels_add_button('go-down.png', 'down', t('Move item down'));
613 }
614 // if ($count > 2) {
615 // $form['bottom'] = panels_add_button('go-bottom.png', 'bottom', t('Move item to bottom'));
616 // }
617 // if ($count > 1) {
618 // $form['spacer'] = panels_add_blank();
619 // }
620 return $form;
621 }
622
623 /**
624 * move an item in an array to the top
625 */
626 function panels_move_top(&$array, &$position) {
627 $value = $array[$position];
628 unset($array[$position]);
629 array_unshift($array, $value);
630 // reindex the array now
631 $array = array_values($array);
632 }
633
634 /**
635 * move an item in an array to the bottom
636 */
637 function panels_move_bottom(&$array, &$position) {
638 $value = $array[$position];
639 unset($array[$position]);
640 $array[] = $value;
641 // reindex the array now
642 $array = array_values($array);
643 }
644
645 /**
646 * move an item in an array up one position
647 */
648 function panels_move_up(&$array, &$position) {
649 $value = $array[$position];
650 $array[$position] = $array[$position - 1];
651 $array[$position - 1] = $value;
652 }
653
654 /**
655 * move an item in an array up one position
656 */
657 function panels_move_down(&$array, &$position) {
658 $value = $array[$position];
659 $array[$position] = $array[$position + 1];
660 $array[$position + 1] = $value;
661 }
662
663 /**
664 * Remove an item from an array
665 */
666 function panels_move_delete(&$array, &$position) {
667 unset($array[$position]);
668 // reindex the array now
669 $array = array_values($array);
670 }
671
672 // ---------------------------------------------------------------------------
673 // panels database functions
674
675 function panels_load_panels($did) {
676 $panels = db_fetch_object(db_query("SELECT * FROM {panels_info} WHERE did = %d", $did));
677 if (!$panels) {
678 return NULL;
679 }
680 $panels->content = array();
681 $panels->access = ($panels->access ? explode(', ', $panels->access) : array());
682
683 $result = db_query("SELECT * FROM {panels_area} WHERE did = %d ORDER BY area, position", $did);
684 while ($area = db_fetch_object($result)) {
685 $area->configuration = unserialize($area->configuration);
686 $panels->content[$area->area][] = $area;
687 }
688 return $panels;
689 }
690
691 function panels_save_panels($panels) {
692 $panels->access = implode(', ', $panels->access);
693 if ($panels->did) {
694 db_query("UPDATE {panels_info} SET title = '%s', access = '%s', path = '%s', css_id = '%s', layout = '%s' WHERE did = %d", $panels->title, $panels->access, $panels->path, $panels->css_id, $panels->layout, $panels->did);
695 db_query("DELETE FROM {panels_area} WHERE did = %d", $panels->did);
696 }
697 else {
698 $panels->did = db_next_id("{panels_info_id}");
699 // Put this in the form so modules can utilize the did of a new panel.
700 $GLOBALS['form_values']['did'] = $panels->did;
701 db_query("INSERT INTO {panels_info} (did, title, access, path, css_id, layout) VALUES (%d, '%s', '%s', '%s', '%s', '%s')", $panels->did, $panels->title, $panels->access, $panels->path, $panels->css_id, $panels->layout);
702 }
703 foreach ($panels->content as $area => $info) {
704 foreach ($info as $position => $block) {
705 if (is_numeric($position)) { // don't save some random form stuff that may've been here.
706 $block = (object) $block;
707 db_query("INSERT INTO {panels_area} (did, area, type, configuration, position) VALUES(%d, '%s', '%s', '%s', %d)", $panels->did, $area, $block->type, serialize($block->configuration), $position);
708 }
709 }
710 }
711 cache_clear_all('menu:', TRUE);
712 }
713
714 function panels_delete_panels($panels) {
715 db_query("DELETE FROM {panels_info} WHERE did = %d", $panels->did);
716 db_query("DELETE FROM {panels_area} WHERE did = %d", $panels->did);
717 cache_clear_all('menu:', TRUE);
718 }
719 // ---------------------------------------------------------------------------
720 // panels page
721
722 /**
723 * Returns TRUE if the current page contains a panels layout.
724 * This can be checked in a theme to hide existing sidebars on panel pages, for example.
725 *
726 * @param $set (optional) used internally to set the page status
727 */
728 function panels_is_panels_page($set_panels = NULL) {
729 static $is_panels;
730 if ($set_panels == TRUE) {
731 $is_panels = $set_panels;
732 }
733 return $is_panels;
734 }
735
736 function panels_panels_page($did) {
737 $panels = panels_load_panels($did);
738 if (!$panels) {
739 return drupal_not_found();
740 }
741
742 $layouts = panels_get_layouts();
743 $layout = $layouts[$panels->layout];
744 $layout['css_id'] = $panels->css_id;
745
746 if (!$layout) {
747 watchdog('panels', t('Unable to find requested layout %s', array('%s' => check_plain($panels->layout))));
748 return drupal_not_found();
749 }
750
751 panels_is_panels_page(TRUE);
752 $content_types = panels_get_content_types();
753
754 foreach ($panels->content as $location => $list) {
755 foreach ($list as $area) {
756 $function = $content_types[$area->type]['callback'];
757 if (function_exists($function)) {
758 $content[$area->area] .= $function($area->configuration);
759 }
760 }
761 }
762 $output = panels_get_layout($layout, $content);
763 drupal_set_title(filter_xss_admin($panels->title));
764 return $output;
765 }
766
767 function panels_get_layout($layout, $content) {
768 $output = theme($layout['theme'], check_plain($layout['css_id']), $content);
769
770 if ($output) {
771 if (file_exists(path_to_theme() . '/' . $layout['css'])) {
772 theme_add_style(path_to_theme() . '/' . $layout['css']);
773 }
774 else {
775 theme_add_style(drupal_get_path('module', $layout['module']) . '/' . $layout['css']);
776 }
777 }
778 return $output;
779 }
780
781 /**
782 * For external use: Given a layout ID and a $content array, return the
783 * finished layout.
784 */
785 function panels_print_layout($id, $content) {
786 $layouts = panels_get_layouts();
787 $layout = $layouts[$id];
788 if (!$layout) {
789 return;
790 }
791
792 return panels_get_layout($layout, $content);
793 }
794
795 // ---------------------------------------------------------------------------
796 // panels data loading
797
798 function panels_load_includes($directory, $callback) {
799 // Load all our module 'on behalfs'.
800 $path = drupal_get_path('module', 'panels') . '/' . $directory;
801 $files = system_listing('.inc$', $path, 'name', 0);
802
803 foreach($files as $file) {
804 require_once('./' . $file->filename);
805 }
806 $output = module_invoke_all($callback);
807 foreach ($files as $file) {
808 $function = 'panels_' . $file->name . '_' . $callback;
809 if (function_exists($function)) {
810 $result = $function();
811 if (isset($result) && is_array($result)) {
812 $output = array_merge($output, $result);
813 }
814 }
815 }
816 return $output;
817 }
818
819 function panels_get_layouts() {
820 static $layout = NULL;
821 if (!$layout) {
822 $layouts = panels_load_includes('layouts', 'panels_layouts');
823 }
824 return $layouts;
825 }
826
827 function panels_get_content_types() {
828 static $layout = NULL;
829 if (!$layout) {
830 $layouts = panels_load_includes('content_types', 'panels_content_types');
831 }
832 return $layouts;
833 }
834
835 /**
836 * Helper function for autocompletion of node titles.
837 * This is mostly stolen from clipper.
838 */
839 function panels_node_autocomplete($string) {
840 if ($string != '') { // if there are node_types passed, we'll use those in a MySQL IN query.
841 $result = db_query_range(db_rewrite_sql('SELECT n.title, u.name FROM {node} n INNER JOIN {users} u ON u.uid = n.uid WHERE LOWER(title) LIKE LOWER("%%%s%%")'), $string, 0, 10);
842 $prefix = count($array) ? implode(', ', $array) .', ' : '';
843
844 $matches = array();
845 while ($node = db_fetch_object($result)) {
846 $n = $node->title;
847 // Commas and quotes in terms are special cases, so encode 'em.
848 if (preg_match('/,/', $node->title) || preg_match('/"/', $node->title)) {
849 $n = '"'. preg_replace('/"/', '""', $node->title) .'"';
850 }
851 $matches[$prefix . $n] = '<span class="autocomplete_title">'. check_plain($node->title) .'</span> <span class="autocomplete_user">('. t('by %user', array('%user' => check_plain($node->name))) .')</span>';
852 }
853 print drupal_to_js($matches);
854 exit();
855 }
856 }