| [ Index ] |
PHP Cross Reference of Drupal 6 (yi-drupal) |
[Summary view] [Print] [Text view]
1 <?php 2 // $Id: content.inc,v 1.12.2.13 2010/08/19 20:35:03 merlinofchaos Exp $ 3 4 /** 5 * @file 6 * Contains the tools to handle pluggable content that can be used by other 7 * applications such as Panels or Dashboard. 8 * 9 * See the context-content.html file in advanced help for documentation 10 * of this tool. 11 */ 12 13 /** 14 * Implementation of hook_ctools_plugin_*. 15 * 16 * Give information to CTools about the content types plugin. 17 */ 18 function ctools_ctools_plugin_content_types() { 19 return array( 20 'cache' => FALSE, 21 'process' => 'ctools_content_process', 22 ); 23 } 24 25 /** 26 * Provide defaults for a content type. 27 * 28 * Currently we check for automatically named callbacks to make life a little 29 * easier on the developer. 30 */ 31 function ctools_content_process(&$plugin, $info) { 32 $function_base = $plugin['module'] . '_' . $plugin['name'] . '_content_type_'; 33 34 if (empty($plugin['render callback']) && function_exists($function_base . 'render')) { 35 $plugin['render callback'] = $function_base . 'render'; 36 } 37 38 if (empty($plugin['admin title'])) { 39 if (function_exists($function_base . 'admin_title')) { 40 $plugin['admin title'] = $function_base . 'admin_title'; 41 } 42 else { 43 $plugin['admin title'] = $plugin['title']; 44 } 45 } 46 47 if (empty($plugin['admin info']) && function_exists($function_base . 'admin_info')) { 48 $plugin['admin info'] = $function_base . 'admin_info'; 49 } 50 51 if (!isset($plugin['edit form']) && function_exists($function_base . 'edit_form')) { 52 $plugin['edit form'] = $function_base . 'edit_form'; 53 } 54 55 if (!isset($plugin['add form']) && function_exists($function_base . 'add_form')) { 56 $plugin['add form'] = $function_base . 'add_form'; 57 } 58 59 if (!isset($plugin['add form']) && function_exists($function_base . 'edit_form')) { 60 $plugin['add form'] = $function_base . 'edit_form'; 61 } 62 63 // Another ease of use check: 64 if (!isset($plugin['content types'])) { 65 // If a subtype plugin exists, try to use it. Otherwise assume single. 66 if (function_exists($function_base . 'content_types')) { 67 $plugin['content types'] = $function_base . 'content_types'; 68 } 69 else { 70 $type = array( 71 'title' => $plugin['title'], 72 'description' => $plugin['description'], 73 'icon' => $plugin['icon'], 74 'category' => $plugin['category'], 75 ); 76 77 if (isset($plugin['required context'])) { 78 $type['required context'] = $plugin['required context']; 79 } 80 if (isset($plugin['top level'])) { 81 $type['top level'] = $plugin['top level']; 82 } 83 $plugin['content types'] = array($plugin['name'] => $type); 84 if (!isset($plugin['single'])) { 85 $plugin['single'] = TRUE; 86 } 87 } 88 } 89 } 90 91 /** 92 * Fetch metadata on a specific content_type plugin. 93 * 94 * @param $content type 95 * Name of a panel content type. 96 * 97 * @return 98 * An array with information about the requested panel content type. 99 */ 100 function ctools_get_content_type($content_type) { 101 ctools_include('context'); 102 ctools_include('plugins'); 103 return ctools_get_plugins('ctools', 'content_types', $content_type); 104 } 105 106 /** 107 * Fetch metadata for all content_type plugins. 108 * 109 * @return 110 * An array of arrays with information about all available panel content types. 111 */ 112 function ctools_get_content_types() { 113 ctools_include('context'); 114 ctools_include('plugins'); 115 return ctools_get_plugins('ctools', 'content_types'); 116 } 117 118 /** 119 * Get all of the individual subtypes provided by a given content type. This 120 * would be all of the blocks for the block type, or all of the views for 121 * the view type. 122 * 123 * @param $type 124 * The content type to load. 125 * 126 * @return 127 * An array of all subtypes available. 128 */ 129 function ctools_content_get_subtypes($type) { 130 static $cache = array(); 131 132 $subtypes = array(); 133 134 if (is_array($type)) { 135 $plugin = $type; 136 } 137 else { 138 $plugin = ctools_get_content_type($type); 139 } 140 141 if (empty($plugin) || empty($plugin['name'])) { 142 return; 143 } 144 145 if (isset($cache[$plugin['name']])) { 146 return $cache[$plugin['name']]; 147 } 148 149 if (isset($plugin['content types'])) { 150 $function = $plugin['content types']; 151 if (is_array($function)) { 152 $subtypes = $function; 153 } 154 else if (function_exists($function)) { 155 // Cast to array to prevent errors from non-array returns. 156 $subtypes = (array) $function($plugin); 157 } 158 } 159 160 // Walk through the subtypes and ensure minimal settings are 161 // retained. 162 foreach ($subtypes as $id => $subtype) { 163 // Use exact name since this is a modify by reference. 164 ctools_content_prepare_subtype($subtypes[$id], $plugin); 165 } 166 167 $cache[$plugin['name']] = $subtypes; 168 169 return $subtypes; 170 } 171 172 /** 173 * Given a content type and a subtype id, return the information about that 174 * content subtype. 175 * 176 * @param $type 177 * The content type being fetched. 178 * @param $subtype_id 179 * The id of the subtype being fetched. 180 * 181 * @return 182 * An array of information describing the content subtype. 183 */ 184 function ctools_content_get_subtype($type, $subtype_id) { 185 $subtype = array(); 186 if (is_array($type)) { 187 $plugin = $type; 188 } 189 else { 190 $plugin = ctools_get_content_type($type); 191 } 192 193 $function = ctools_plugin_get_function($plugin, 'content type'); 194 if ($function) { 195 $subtype = $function($subtype_id, $plugin); 196 } 197 else { 198 $subtypes = ctools_content_get_subtypes($type); 199 if (isset($subtypes[$subtype_id])) { 200 $subtype = $subtypes[$subtype_id]; 201 } 202 // If there's only 1 and we somehow have the wrong subtype ID, do not 203 // care. Return the proper subtype anyway. 204 if (empty($subtype) && !empty($plugin['single'])) { 205 $subtype = current($subtypes); 206 } 207 } 208 209 if ($subtype) { 210 ctools_content_prepare_subtype($subtype, $plugin); 211 } 212 return $subtype; 213 } 214 215 /** 216 * Ensure minimal required settings on a content subtype exist. 217 */ 218 function ctools_content_prepare_subtype(&$subtype, $plugin) { 219 foreach (array('path', 'js', 'css') as $key) { 220 if (!isset($subtype[$key]) && isset($plugin[$key])) { 221 $subtype[$key] = $plugin[$key]; 222 } 223 } 224 } 225 226 /** 227 * Get the content from a given content type. 228 * 229 * @param $type 230 * The content type. May be the name or an already loaded content type plugin. 231 * @param $subtype 232 * The name of the subtype being rendered. 233 * @param $conf 234 * The configuration for the content type. 235 * @param $keywords 236 * An array of replacement keywords that come from outside contexts. 237 * @param $args 238 * The arguments provided to the owner of the content type. Some content may 239 * wish to configure itself based on the arguments the panel or dashboard 240 * received. 241 * @param $context 242 * An array of context objects available for use. 243 * @param $incoming_content 244 * Any incoming content, if this display is a wrapper. 245 * 246 * @return 247 * The content as rendered by the plugin. This content should be an array 248 * with the following possible keys: 249 * - title: The safe to render title of the content. 250 * - content: The safe to render HTML content. 251 * - links: An array of links associated with the content suitable for 252 * theme('links'). 253 * - more: An optional 'more' link (destination only) 254 * - admin_links: Administrative links associated with the content, suitable 255 * for theme('links'). 256 * - feeds: An array of feed icons or links associated with the content. 257 * Each member of the array is rendered HTML. 258 * - type: The content type. 259 * - subtype: The content subtype. These two may be used together as 260 * module-delta for block style rendering. 261 */ 262 function ctools_content_render($type, $subtype, $conf, $keywords = array(), $args = array(), $context = array(), $incoming_content = '') { 263 if (is_array($type)) { 264 $plugin = $type; 265 } 266 else { 267 $plugin = ctools_get_content_type($type); 268 } 269 270 $subtype_info = ctools_content_get_subtype($plugin, $subtype); 271 272 $function = ctools_plugin_get_function($subtype_info, 'render callback'); 273 if (!$function) { 274 $function = ctools_plugin_get_function($plugin, 'render callback'); 275 } 276 277 if ($function) { 278 $pane_context = ctools_content_select_context($plugin, $subtype, $conf, $context); 279 if ($pane_context === FALSE) { 280 return; 281 } 282 283 $content = $function($subtype, $conf, $args, $pane_context, $incoming_content); 284 285 // Set up some defaults and other massaging on the content before we hand 286 // it back to the caller. 287 if (!isset($content->type)) { 288 $content->type = $plugin['name']; 289 } 290 291 if (!isset($content->subtype)) { 292 $content->subtype = $subtype; 293 } 294 295 // Override the title if configured to 296 if (!empty($conf['override_title'])) { 297 // Give previous title as an available substitution here. 298 $keywords['%title'] = empty($content->title) ? '' : $content->title; 299 $content->original_title = $keywords['%title']; 300 $content->title = $conf['override_title_text']; 301 } 302 303 if (!empty($content->title)) { 304 // Perform substitutions 305 if (!empty($keywords) || !empty($context)) { 306 $content->title = ctools_context_keyword_substitute($content->title, $keywords, $context); 307 } 308 309 // Sterilize the title 310 $content->title = filter_xss_admin($content->title); 311 312 // If a link is specified, populate. 313 if (!empty($content->title_link)) { 314 if (!is_array($content->title_link)) { 315 $url = array('href' => $content->title_link); 316 } 317 else { 318 $url = $content->title_link; 319 } 320 // set defaults so we don't bring up notices 321 $url += array('href' => '', 'attributes' => NULL, 'query' => NULL, 'fragment' => NULL, 'absolute' => NULL, 'html' => TRUE); 322 $content->title = l($content->title, $url['href'], $url); 323 } 324 } 325 326 return $content; 327 } 328 } 329 330 /** 331 * Determine if a content type can be edited or not. 332 * 333 * Some content types simply have their content and no options. This function 334 * lets a UI determine if it should display an edit link or not. 335 */ 336 function ctools_content_editable($type, $subtype, $conf) { 337 if (empty($type['edit form']) && empty($subtype['edit form'])) { 338 return FALSE; 339 } 340 341 if ($function = ctools_plugin_get_function($subtype, 'check editable')) { 342 return $function($type, $subtype, $conf); 343 } 344 345 return TRUE; 346 } 347 348 /** 349 * Get the administrative title from a given content type. 350 * 351 * @param $type 352 * The content type. May be the name or an already loaded content type object. 353 * @param $subtype 354 * The subtype being rendered. 355 * @param $conf 356 * The configuration for the content type. 357 * @param $context 358 * An array of context objects available for use. These may be placeholders. 359 */ 360 function ctools_content_admin_title($type, $subtype, $conf, $context = NULL) { 361 if (is_array($type)) { 362 $plugin = $type; 363 } 364 else if (is_string($type)) { 365 $plugin = ctools_get_content_type($type); 366 } 367 else { 368 return; 369 } 370 371 if ($function = ctools_plugin_get_function($plugin, 'admin title')) { 372 $pane_context = ctools_content_select_context($plugin, $subtype, $conf, $context); 373 if ($pane_context === FALSE) { 374 if ($plugin['name'] == $subtype) { 375 return t('@type will not display due to missing context', array('@type' => $plugin['name'])); 376 } 377 return t('@type:@subtype will not display due to missing context', array('@type' => $plugin['name'], '@subtype' => $subtype)); 378 } 379 380 return $function($subtype, $conf, $pane_context); 381 } 382 else if (isset($plugin['admin title'])) { 383 return $plugin['admin title']; 384 } 385 else if (isset($plugin['title'])) { 386 return $plugin['title']; 387 } 388 } 389 390 /** 391 * Get the proper icon path to use, falling back to default icons if no icon exists. 392 * 393 * $subtype 394 * The loaded subtype info. 395 */ 396 function ctools_content_admin_icon($subtype) { 397 $icon = ''; 398 399 if (isset($subtype['icon'])) { 400 $icon = $subtype['icon']; 401 if (!file_exists($icon)) { 402 $icon = $subtype['path'] . '/' . $icon; 403 } 404 } 405 406 if (empty($icon) || !file_exists($icon)) { 407 $icon = ctools_image_path('no-icon.png'); 408 } 409 410 return $icon; 411 } 412 413 /** 414 * Set up the default $conf for a new instance of a content type. 415 */ 416 function ctools_content_get_defaults($plugin, $subtype) { 417 if (isset($plugin['defaults'])) { 418 $defaults = $plugin['defaults']; 419 } 420 else if (isset($subtype['defaults'])) { 421 $defaults = $subtype['defaults']; 422 } 423 if (isset($defaults)) { 424 if (is_string($defaults) && function_exists($defaults)) { 425 if ($return = $defaults($pane)) { 426 return $return; 427 } 428 } 429 else if (is_array($defaults)) { 430 return $defaults; 431 } 432 } 433 434 return array(); 435 } 436 437 /** 438 * Get the administrative title from a given content type. 439 * 440 * @param $type 441 * The content type. May be the name or an already loaded content type object. 442 * @param $subtype 443 * The subtype being rendered. 444 * @param $conf 445 * The configuration for the content type. 446 * @param $context 447 * An array of context objects available for use. These may be placeholders. 448 */ 449 function ctools_content_admin_info($type, $subtype, $conf, $context = NULL) { 450 if (is_array($type)) { 451 $plugin = $type; 452 } 453 else { 454 $plugin = ctools_get_content_type($type); 455 } 456 457 if ($function = ctools_plugin_get_function($plugin, 'admin info')) { 458 $output = $function($subtype, $conf, $context); 459 } 460 if (empty($output) || !is_object($output)) { 461 $output = new stdClass(); 462 $output->title = t('No info'); 463 $output->content =t ('No info available.'); 464 } 465 return $output; 466 } 467 468 /** 469 * Add the default FAPI elements to the content type configuration form 470 */ 471 function ctools_content_configure_form_defaults(&$form, &$form_state) { 472 $plugin = $form_state['plugin']; 473 $subtype = $form_state['subtype']; 474 $contexts = isset($form_state['contexts']) ? $form_state['contexts'] : NULL; 475 $conf = $form_state['conf']; 476 477 $add_submit = FALSE; 478 if (!empty($subtype['required context']) && is_array($contexts)) { 479 $form['context'] = ctools_context_selector($contexts, $subtype['required context'], isset($conf['context']) ? $conf['context'] : array()); 480 $add_submit = TRUE; 481 } 482 483 ctools_include('dependent'); 484 485 // Unless we're not allowed to override the title on this content type, add this 486 // gadget to all panes. 487 if (empty($plugin['no title override']) && empty($subtype['no title override'])) { 488 $form['aligner_start'] = array( 489 '#value' => '<div class="option-text-aligner">', 490 ); 491 $form['override_title'] = array( 492 '#type' => 'checkbox', 493 '#default_value' => isset($conf['override_title']) ? $conf['override_title'] : '', 494 '#title' => t('Override title'), 495 '#id' => 'override-title-checkbox', 496 ); 497 $form['override_title_text'] = array( 498 '#type' => 'textfield', 499 '#default_value' => isset($conf['override_title_text']) ? $conf['override_title_text'] : '', 500 '#size' => 35, 501 '#id' => 'override-title-textfield', 502 '#process' => array('ctools_dependent_process'), 503 '#dependency' => array('override-title-checkbox' => array(1)), 504 '#dependency_type' => 'disable', 505 ); 506 $form['aligner_stop'] = array( 507 '#value' => '</div><div style="clear: both; padding: 0; margin: 0"></div>', 508 ); 509 if (is_array($contexts)) { 510 $form['override_title_markup'] = array( 511 '#prefix' => '<div class="description">', 512 '#suffix' => '</div>', 513 '#value' => t('You may use %keywords from contexts, as well as %title to contain the original title.'), 514 ); 515 } 516 $add_submit = TRUE; 517 } 518 519 if ($add_submit) { 520 // '#submit' is already set up due to the wizard. 521 $form['#submit'][] = 'ctools_content_configure_form_defaults_submit'; 522 } 523 return $form; 524 } 525 526 /** 527 * Submit handler to store context/title override info. 528 */ 529 function ctools_content_configure_form_defaults_submit(&$form, &$form_state) { 530 if (isset($form_state['values']['context'])) { 531 $form_state['conf']['context'] = $form_state['values']['context']; 532 } 533 if (isset($form_state['values']['override_title'])) { 534 $form_state['conf']['override_title'] = $form_state['values']['override_title']; 535 $form_state['conf']['override_title_text'] = $form_state['values']['override_title_text']; 536 } 537 } 538 539 /** 540 * Get the config form. 541 * 542 * The $form_info and $form_state need to be preconfigured with data you'll need 543 * such as whether or not you're using ajax, or the modal. $form_info will need 544 * your next/submit callbacks so that you can cache your data appropriately. 545 * 546 * @return 547 * If this function returns false, no form exists. 548 */ 549 function ctools_content_form($op, $form_info, &$form_state, $plugin, $subtype_name, $subtype, &$conf, $step = NULL) { 550 $form_state += array( 551 'plugin' => $plugin, 552 'subtype' => $subtype, 553 'subtype_name' => $subtype_name, 554 'conf' => &$conf, 555 'op' => $op, 556 ); 557 558 $form_info += array( 559 'id' => 'ctools_content_form', 560 'show back' => TRUE, 561 ); 562 563 // Turn the forms defined in the plugin into the format the wizard needs. 564 if ($op == 'add') { 565 if (!empty($subtype['add form'])) { 566 _ctools_content_create_form_info($form_info, $subtype['add form'], $subtype, $subtype, $op); 567 } 568 else if (!empty($plugin['add form'])) { 569 _ctools_content_create_form_info($form_info, $plugin['add form'], $plugin, $subtype, $op); 570 } 571 } 572 573 if (empty($form_info['order'])) { 574 // Use the edit form for the add form if add form was completely left off. 575 if (!empty($subtype['edit form'])) { 576 _ctools_content_create_form_info($form_info, $subtype['edit form'], $subtype, $subtype, $op); 577 } 578 else if (!empty($plugin['edit form'])) { 579 _ctools_content_create_form_info($form_info, $plugin['edit form'], $plugin, $subtype, $op); 580 } 581 } 582 583 if (empty($form_info['order'])) { 584 return FALSE; 585 } 586 587 ctools_include('wizard'); 588 return ctools_wizard_multistep_form($form_info, $step, $form_state); 589 590 } 591 592 function _ctools_content_create_form_info(&$form_info, $info, $plugin, $subtype, $op) { 593 if (is_string($info)) { 594 if (empty($subtype['title'])) { 595 $title = t('Configure'); 596 } 597 else if ($op == 'add') { 598 $title = t('Configure new !subtype_title', array('!subtype_title' => $subtype['title'])); 599 } 600 else { 601 $title = t('Configure !subtype_title', array('!subtype_title' => $subtype['title'])); 602 } 603 $form_info['order'] = array('form' => $title); 604 $form_info['forms'] = array( 605 'form' => array( 606 'title' => $title, 607 'form id' => $info, 608 'wrapper' => 'ctools_content_configure_form_defaults', 609 ), 610 ); 611 } 612 else if (is_array($info)) { 613 $form_info['order'] = array(); 614 $form_info['forms'] = array(); 615 $count = 0; 616 $base = 'step'; 617 $wrapper = NULL; 618 foreach ($info as $form_id => $title) { 619 // @todo -- docs say %title can be used to sub for the admin title. 620 $step = $base . ++$count; 621 if (empty($wrapper)) { 622 $wrapper = $step; 623 } 624 625 if (is_array($title)) { 626 if (!empty($title['default'])) { 627 $wrapper = $step; 628 } 629 $title = $title['title']; 630 } 631 632 $form_info['order'][$step] = $title; 633 $form_info['forms'][$step] = array( 634 'title' => $title, 635 'form id' => $form_id, 636 ); 637 } 638 if ($wrapper) { 639 $form_info['forms'][$wrapper]['wrapper'] = 'ctools_content_configure_form_defaults'; 640 } 641 } 642 } 643 644 /** 645 * Get an array of all available content types that can be fed into the 646 * display editor for the add content list. 647 * 648 * @param $context 649 * If a context is provided, content that requires that context can apepar. 650 * @param $has_content 651 * Whether or not the display will have incoming content 652 * @param $allowed_types 653 * An array of allowed content types (pane types) keyed by content_type . '-' . sub_type 654 * @param $default_types 655 * A default allowed/denied status for content that isn't known about 656 */ 657 function ctools_content_get_available_types($contexts = NULL, $has_content = FALSE, $allowed_types = NULL, $default_types = NULL) { 658 $plugins = ctools_get_content_types(); 659 $available = array(); 660 661 foreach ($plugins as $id => $plugin) { 662 foreach (ctools_content_get_subtypes($plugin) as $subtype_id => $subtype) { 663 // exclude items that require content if we're saying we don't 664 // provide it. 665 if (!empty($subtype['requires content']) && !$has_content) { 666 continue; 667 } 668 669 // Check to see if the content type can be used in this context. 670 if (!empty($subtype['required context'])) { 671 if (!ctools_context_match_requirements($contexts, $subtype['required context'])) { 672 continue; 673 } 674 } 675 676 // Check to see if the passed-in allowed types allows this content. 677 if ($allowed_types) { 678 $key = $id . '-' . $subtype_id; 679 if (!isset($allowed_types[$key])) { 680 $allowed_types[$key] = isset($default_types[$id]) ? $default_types[$id] : $default_types['other']; 681 } 682 if (!$allowed_types[$key]) { 683 continue; 684 } 685 } 686 687 // If we made it through all the tests, then we can use this content. 688 $available[$id][$subtype_id] = $subtype; 689 } 690 } 691 return $available; 692 } 693 694 /** 695 * Get an array of all content types that can be fed into the 696 * display editor for the add content list, regardless of 697 * availability. 698 * 699 */ 700 function ctools_content_get_all_types() { 701 $plugins = ctools_get_content_types(); 702 $available = array(); 703 704 foreach ($plugins as $id => $plugin) { 705 foreach (ctools_content_get_subtypes($plugin) as $subtype_id => $subtype) { 706 // If we made it through all the tests, then we can use this content. 707 $available[$id][$subtype_id] = $subtype; 708 } 709 } 710 return $available; 711 } 712 713 /** 714 * Select the context to be used for a piece of content, based upon config. 715 * 716 * @param $plugin 717 * The content plugin 718 * @param $subtype 719 * The subtype of the content. 720 * @param $conf 721 * The configuration array that should contain the context. 722 * @param $contexts 723 * A keyed array of available contexts. 724 * 725 * @return 726 * The matching contexts or NULL if none or necessary, or FALSE if 727 * requirements can't be met. 728 */ 729 function ctools_content_select_context($plugin, $subtype, $conf, $contexts) { 730 // Identify which of our possible contexts apply. 731 if (empty($subtype)) { 732 return; 733 } 734 735 $subtype_info = ctools_content_get_subtype($plugin, $subtype); 736 if (empty($subtype_info)) { 737 return; 738 } 739 740 if (!empty($subtype_info['all contexts']) || !empty($plugin['all contexts'])) { 741 return $contexts; 742 } 743 744 // If the content requires a context, fetch it; if no context is returned, 745 // do not display the pane. 746 if (empty($subtype_info['required context'])) { 747 return; 748 } 749 750 if (empty($conf['context'])) { 751 return; 752 } 753 754 $context = ctools_context_select($contexts, $subtype_info['required context'], $conf['context']); 755 756 return $context; 757 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
| Generated: Mon Jul 9 18:01:44 2012 | Cross-referenced by PHPXref 0.7 |