display_edit.inc

Go to the documentation of this file.
00001 <?php
00002 // $Id: display_edit.inc,v 1.1.2.63 2008/08/03 04:34:01 sdboyer Exp $
00003 
00004 
00005 /*
00006  * @file display_edit.inc
00007  * Core Panels API include file containing various display-editing functions.
00008  * This includes all the basic editing forms (content, layout, layout settings)
00009  * as well as the ajax modal forms associated with them.
00010  */
00011 
00012 /**
00013  * Handle calling and processing of the form for editing display content.
00014  *
00015  * Helper function for panels_edit().
00016  *
00017  * @see panels_edit() for details on the various behaviors of this function.
00018  */
00019 function _panels_edit($display, $destination, $content_types) {
00020   $did = $display->did;
00021   if (!$did) {
00022     $display->did = $did = 'new';
00023   }
00024 
00025   // Load the display being edited from cache, if possible.
00026   if (!empty($_POST) && is_object($cache = panels_cache_get($did))) {
00027     $display = $cache->display;
00028   }
00029   else {
00030     panels_cache_clear($did);
00031     $cache = new stdClass();
00032     $cache->display = $display;
00033     $cache->content_types = $content_types;
00034     panels_cache_set($did, $cache);
00035   }
00036 
00037   // Break out the form pieces so we can return the new $display upon
00038   // successful submit.
00039 
00040   $form_id = 'panels_edit_display';
00041   $form = drupal_retrieve_form($form_id, $display, $destination);
00042 
00043   if ($result = drupal_process_form($form_id, $form)) {
00044     // successful submit
00045     return $result;
00046   }
00047 
00048   $output = drupal_render_form($form_id, $form);
00049   $output .= theme('panels_hidden');
00050   return $output;
00051 }
00052 
00053 /**
00054  * Form definition for the panels display editor
00055  *
00056  * No validation function is necessary, as all 'validation' is handled
00057  * either in the lead-up to form rendering (through the selection of
00058  * specified content types) or by the validation functions specific to
00059  * the ajax modals & content types.
00060  *
00061  * @ingroup forms
00062  * @see panels_edit_display_submit()
00063  */
00064 function panels_edit_display($display, $destination) {
00065   $form['did'] = array(
00066     '#type' => 'hidden',
00067     '#value' => $display->did,
00068     '#id' => 'panel-did',
00069   );
00070 
00071   $form['op'] = array(
00072     '#type' => 'hidden',
00073     '#id' => 'panel-op',
00074   );
00075 
00076   $form['panels_display'] = array(
00077     '#type' => 'value',
00078     '#value' => $display,
00079   );
00080 
00081   if (!empty($destination)) {
00082     $form['destination'] = array(
00083       '#type' => 'value',
00084       '#value' => $destination,
00085     );
00086   }
00087   else {
00088     $form['#redirect'] = FALSE;
00089   }
00090 
00091   $explanation_text = '<p>';
00092   $explanation_text .= t('Grab the title bar of any pane to drag-and-drop it into another panel. Click the add pane button (!addicon) in any panel to add more content. Click the configure (!configicon) button on any pane to re-configure that pane. Click the cache (!cacheicon) button to configure caching for that pane specifically. Click the show/hide (!showicon/!hideicon) toggle button to show or hide that pane. Panes hidden in this way will be hidden from <em>everyone</em> until the hidden status is toggled off.',
00093     array(
00094       '!addicon' => '<span class="inline-icon-help">' . theme('image', panels_get_path('images/icon-addcontent.png'), t('Add content to this panel'), t('Add content to this panel')) . '</span>',
00095       '!configicon' => '<span class="inline-icon-help">' . theme('image', panels_get_path('images/icon-configure.png'), t('Configure this pane'), t('Configure this pane')) . '</span>',
00096       '!cacheicon' => '<span class="inline-icon-help">' . theme('image', panels_get_path('images/icon-cache.png'), t('Control caching'), t('Control caching')) . '</span>',
00097       '!showicon' => '<span class="inline-icon-help">' . theme('image', panels_get_path('images/icon-showpane.png'), t('Show this pane'), t('Show this pane')) . '</span>',
00098       '!hideicon' => '<span class="inline-icon-help">' . theme('image', panels_get_path('images/icon-hidepane.png'), t('Hide this pane'), t('Hide this pane')) . '</span>',
00099     )
00100   );
00101   $explanation_text .= '</p>';
00102 
00103   $form['explanation'] = array(
00104     '#value' => $explanation_text,
00105   );
00106 
00107   $layout = panels_get_layout($display->layout);
00108   $layout_panels = panels_get_panels($layout, $display);
00109 
00110   $form['button']['#tree'] = TRUE;
00111   $caches = panels_get_caches();
00112 
00113   foreach ($display->content as $pid => $pane) {
00114     // This test ensures we don't put anything for panes that are in panels
00115     // that don't exist -- as can happen when flexible changes.
00116     if ($layout_panels[$pane->panel]) {
00117       $form['button'][$pid]['#tree'] = TRUE;
00118       if ($caches && user_access('use panels caching features')) {
00119         $form['button'][$pid]['cache'] = panels_add_button('icon-cache.png', t('Caching'), t('Control caching'), 'pane-cache');
00120       }
00121       $form['button'][$pid]['show_hide'] = panels_add_button($pane->shown ? 'icon-hidepane.png' : 'icon-showpane.png', t('Show/Hide Toggle'), $pane->shown ? t('Hide this pane') : t('Show this pane'), 'pane-toggle-shown');
00122       $form['button'][$pid]['configure'] = panels_add_button('icon-configure.png', t('Configure'), t('Configure this pane'), 'pane-configure');
00123       $form['button'][$pid]['delete'] = panels_add_button('icon-delete.png', t('Delete'), t('Remove this pane'), 'pane-delete');
00124     }
00125   }
00126 
00127   foreach ($layout_panels as $id => $name) {
00128     $form['panels'][$id]['add'] = panels_add_button('icon-addcontent.png', t('Add content'), t('Add content to this panel'), 'pane-add', "pane-add-$id");
00129   }
00130 
00131   $form['panel'] = array('#tree' => TRUE);
00132   $form['panel']['pane'] = array('#tree' => TRUE);
00133 
00134   foreach ($layout_panels as $panel_id => $title) {
00135     $form['panel']['pane'][$panel_id] = array(
00136       // Use 'hidden' instead of 'value' so the js can access it.
00137       '#type' => 'hidden',
00138       '#default_value' => implode(',', (array) $display->panels[$panel_id]),
00139     );
00140   }
00141   $form['submit'] = array(
00142     '#type' => 'submit',
00143     '#value' => t('Save'),
00144     '#id' => 'panels-dnd-save',
00145   );
00146   $form['cancel'] = array(
00147     '#type' => 'submit',
00148     '#value' => t('Cancel'),
00149   );
00150 
00151   $form['hide'] = array(
00152     '#prefix' => '<span id="panels-js-only">',
00153     '#suffix' => '</span>',
00154   );
00155 
00156   $form['hide']['hide-all'] = array(
00157     '#type' => 'submit',
00158     '#value' => t('Hide all'),
00159     '#id' => 'panels-hide-all',
00160   );
00161 
00162   $form['hide']['show-all'] = array(
00163     '#type' => 'submit',
00164     '#value' => t('Show all'),
00165     '#id' => 'panels-show-all',
00166   );
00167 
00168   $form['hide']['cache-settings'] = array(
00169     '#type' => 'submit',
00170     '#value' => t('Cache settings'),
00171     '#id' => 'panels-cache-settings',
00172   );
00173 
00174   return $form;
00175 }
00176 
00177 /**
00178  * Theme the form for editing display content.
00179  *
00180  * @ingroup themeable
00181  *
00182  * @param array $form
00183  *  A structured FAPI $form array.
00184  *
00185  * @return string $output
00186  *  HTML ready to be rendered. Note that the html produced here should be printed,
00187  *  not returned, as it bypasses block rendering. Block rendering must be bypassed
00188  *  because sidebars created using negative margins break ajax drag-and-drop.
00189  */
00190 function theme_panels_edit_display($form) {
00191   _panels_js_files();
00192   $display = $form['panels_display']['#value'];
00193   $layout = panels_get_layout($display->layout);
00194   $layout_panels = panels_get_panels($layout, $display);
00195   $save_buttons = drupal_render($form['submit']) . drupal_render($form['cancel']);
00196 
00197   foreach ($layout_panels as $panel_id => $title) {
00198     foreach ((array) $display->panels[$panel_id] as $pid) {
00199       $pane = $display->content[$pid];
00200       $left_buttons = NULL;
00201       $buttons = drupal_render($form['button'][$pid]['configure']);
00202       if (!empty($form['button'][$pid]['cache'])) {
00203         $buttons .= drupal_render($form['button'][$pid]['cache']);
00204       }
00205       $buttons .= drupal_render($form['button'][$pid]['show_hide']);
00206       $buttons .= drupal_render($form['button'][$pid]['delete']);
00207       $content[$pane->panel] .= panels_show_pane($display, $pane, $left_buttons, $buttons);
00208     }
00209     $content[$panel_id] = theme('panels_panel_dnd', $content[$panel_id], $panel_id, $title, drupal_render($form['panels'][$panel_id]['add']));
00210   }
00211   $output .= drupal_render($form);
00212   $output .= theme('panels_dnd', panels_render_layout($layout, $content, '', $display->layout_settings));
00213   $output .= $save_buttons;
00214   return $output;
00215 }
00216 
00217 /**
00218  * Handle form submission of the display content editor.
00219  *
00220  * The behavior of this function is fairly complex and irregular compared to
00221  * most FAPI submit handlers. See the documentation on panels_edit() for a
00222  * detailed discussion of this behavior.
00223  */
00224 function panels_edit_display_submit($form_id, $form_values) {
00225   $display = $form_values['panels_display'];
00226   if ($form_values['op'] == t('Save')) {
00227     $old_content = $display->content;
00228     $display->content = array();
00229 
00230     foreach ($form_values['panel']['pane'] as $panel_id => $panes) {
00231       $display->panels[$panel_id] = array();
00232       if ($panes) {
00233         $pids = explode(',', $panes);
00234         // need to filter the array, b/c passing it in a hidden field can generate trash
00235         foreach (array_filter($pids) as $pid) {
00236           if ($old_content[$pid]) {
00237             $display->panels[$panel_id][] = $pid;
00238             $old_content[$pid]->panel = $panel_id;
00239             $display->content[$pid] = $old_content[$pid];
00240           }
00241         }
00242       }
00243     }
00244     drupal_set_message(t('Panel content has been updated.'));
00245     panels_save_display($display);
00246   }
00247 
00248   panels_cache_clear($display->did);
00249   if (empty($form_values['destination'])) {
00250     return $display;
00251   }
00252 }
00253 
00254 /**
00255  * Handle calling and processing of the form for editing display layouts.
00256  *
00257  * Helper function for panels_edit_layout().
00258  *
00259  * @see panels_edit_layout() for details on the various behaviors of this function.
00260  */
00261 function _panels_edit_layout($display, $finish, $destination, $allowed_layouts) {
00262   panels_load_include('common');
00263   // module_name has been provided; the data was saved by the api_save() method.
00264   if (is_string($allowed_layouts)) {
00265     $allowed_layouts = unserialize(variable_get($allowed_layouts . "_allowed_layouts", serialize('')));
00266   }
00267   // if no parameter was provided, or the variable_get failed
00268   if (!$allowed_layouts) {
00269     // tries to load the common panels allowed layouts
00270     $allowed_layouts = unserialize(variable_get('panels_common_allowed_layouts', serialize('')));
00271     if (!$allowed_layouts) {
00272       // still no dice. simply creates a dummy version where all layouts are allowed.
00273       $allowed_layouts = new panels_allowed_layouts();
00274       $allowed_layouts->allow_new = TRUE;
00275     }
00276   }
00277   // sanitize allowed layout listing; this is redundant if the $allowed_layouts param was null, but the data is cached anyway
00278   $allowed_layouts->sync_with_available();
00279   // Break out the form pieces so we can return the new $display upon
00280   // successful submit.
00281   $form_id = 'panels_choose_layout';
00282   $form = drupal_retrieve_form($form_id, $display, $finish, $destination, array_filter($allowed_layouts->allowed_layout_settings));
00283 
00284   if ($result = drupal_process_form($form_id, $form)) {
00285     // successful submit
00286     return $result;
00287   }
00288   $output = drupal_render_form($form_id, $form);
00289   return $output;
00290 }
00291 
00292 /**
00293  * Form definition for the display layout editor.
00294  *
00295  * @ingroup forms
00296  */
00297 function panels_choose_layout($display, $finish, $destination, $allowed_layouts) {
00298   $layouts = array();
00299   $available_layouts = panels_get_layouts();
00300   foreach ($available_layouts as $layout_key => $layout_settings) {
00301     if (!empty($allowed_layouts[$layout_key])) {
00302       $layouts[$layout_key] = $layout_settings;
00303     }
00304   }
00305   foreach ($layouts as $id => $layout) {
00306     $options[$id] = panels_print_layout_icon($id, $layout, check_plain($layout['title']));
00307   }
00308 
00309   drupal_add_js(panels_get_path('js/layout.js'));
00310   $form['layout'] = array(
00311     '#type' => 'radios',
00312     '#title' => t('Choose layout'),
00313     '#options' => $options,
00314     '#default_value' => in_array($display->layout, array_keys($layouts)) ? $display->layout : NULL,
00315     '#attributes' => array('class' => 'clear-block'),
00316   );
00317 
00318   $form['variables'] = array(
00319     '#type' => 'value',
00320     '#value' => array($display, $finish, $destination),
00321   );
00322 
00323   if (empty($destination)) {
00324     $form['#redirect'] = FALSE;
00325   }
00326 
00327   if ($_POST['op'] && $_POST['op'] != t('Back') && $display->content) {
00328     $form['#post'] = $_POST;
00329     $form = form_builder('panels_choose_layout', $form);
00330     unset($form['#post']);
00331     $form['layout']['#type'] = 'hidden';
00332     panels_change_layout($form, $display, $form['layout']['#value']);
00333   }
00334 
00335   if (($_POST['op'] && $_POST['op'] != t('Back')) || !$display->content) {
00336     $form['submit'] = array(
00337       '#type' => 'submit',
00338       '#value' => $finish,
00339     );
00340   }
00341   else {
00342     $form['submit'] = array(
00343       '#type' => 'submit',
00344       '#value' => t('Next'),
00345     );
00346   }
00347 
00348   // no token please
00349   $form['#token'] = FALSE;
00350   return $form;
00351 }
00352 
00353 /**
00354  * Handle form submission of the display layout editor.
00355  *
00356  * The behavior of this function is fairly complex and irregular compared to
00357  * most FAPI submit handlers. See the documentation on panels_edit_layout() for
00358  * detailed discussion of this behavior.
00359  */
00360 function panels_choose_layout_submit($form_id, $form_values) {
00361   list($display, $finish, $destination) = $form_values['variables'];
00362   $new_layout_id = $form_values['layout'];
00363 
00364   if ($form_values['op'] == $finish) {
00365     if (!empty($form_values['old'])) {
00366       foreach ($form_values['old'] as $id => $new_id) {
00367         $content[$new_id] = array_merge((array) $content[$new_id], $display->panels[$id]);
00368         foreach ($content[$new_id] as $pid) {
00369           $display->content[$pid]->panel = $new_id;
00370         }
00371       }
00372 
00373       $display->panels = $content;
00374     }
00375 
00376     $display->layout = $new_layout_id;
00377 
00378     // save it back to our session.
00379     panels_save_display($display);
00380     if (empty($destination)) {
00381       return $display;
00382     }
00383 
00384     return $destination;
00385   }
00386 
00387   return FALSE;
00388 }
00389 
00390 /**
00391  * Form definition for the display layout converter.
00392  *
00393  * This form is only triggered if the user attempts to change the layout
00394  * for a display that has already had content assigned to it. It allows
00395  * the user to select where the panes located in to-be-deleted panels should
00396  * be relocated to.
00397  *
00398  * @ingroup forms
00399  *
00400  * @param array $form
00401  *  A structured FAPI $form array.
00402  * @param object $display instanceof panels_display \n
00403  *  The panels_display object that was modified on the preceding display layout
00404  *  editing form.
00405  * @param string $new_layout_id
00406  *  A string containing the name of the layout the display is to be converted to.
00407  *  These strings correspond exactly to the filenames of the *.inc files in panels/layouts.
00408  *  So, if the new layout that's been selected is the 'Two Column bricks' layout, then
00409  *  $new_layout_id will be 'twocol_bricks', corresponding to panels/layouts/twocol_bricks.inc.
00410  */
00411 function panels_change_layout(&$form, $display, $new_layout_id) {
00412   $new_layout = panels_get_layout($new_layout_id);
00413   $new_layout_panels = panels_get_panels($new_layout, $display);
00414 
00415   $options = $new_layout_panels;
00416   $keys = array_keys($options);
00417   $default = $options[0];
00418 
00419   $old_layout = panels_get_layout($display->layout);
00420 
00421   $form['container'] = array(
00422     '#prefix' => '<div class="change-layout-display">',
00423     '#suffix' => '</div>',
00424   );
00425 
00426   $form['container']['old_layout'] = array(
00427     '#value' => panels_print_layout_icon($display->layout, $old_layout, check_plain($old_layout['title'])),
00428   );
00429 
00430   $form['container']['right_arrow'] = array(
00431     '#value' => theme('image', drupal_get_path('module', 'panels') . '/images/go-right.png'),
00432   );
00433   $form['container']['new_layout'] = array(
00434     '#value' => panels_print_layout_icon($new_layout_id, $new_layout, check_plain($new_layout['title'])),
00435   );
00436 
00437   $form['container-clearer'] = array(
00438     // TODO: FIx this ot use clear-block instead
00439     '#value' => '<div style="clear: both;"></div>',
00440   );
00441 
00442   $form['old'] = array(
00443     '#tree' => true,
00444     '#prefix' => '<div class="panels-layout-list">',
00445     '#suffix' => '</div>',
00446   );
00447 
00448   $old_layout_panels = panels_get_panels($old_layout, $display);
00449   foreach ($display->panels as $id => $content) {
00450     $form['old'][$id] = array(
00451       '#type' => 'select',
00452       '#title' => t('Move content in @layout to', array('@layout' => $old_layout_panels[$id])),
00453       '#options' => $options,
00454       '#default_value' => array_key_exists($id, $options) ? $id : $default,
00455     );
00456   }
00457 
00458   $form['back'] = array(
00459     '#type' => 'submit',
00460     '#value' => t('Back'),
00461   );
00462   return $form;
00463 }
00464 
00465 /**
00466  * Handle calling and processing of the form for editing display layout settings.
00467  *
00468  * Helper function for panels_edit_layout_settings().
00469  *
00470  * @see panels_edit_layout_settings() for details on the various behaviors of this function.
00471  */
00472 function _panels_edit_layout_settings($display, $finish, $destination, $title) {
00473   // Break out the form pieces so we can return the new $display upon
00474   // successful submit.
00475   $form_id = 'panels_edit_layout_settings_form';
00476   $form = drupal_retrieve_form($form_id, $display, $finish, $destination, $title);
00477 
00478   if ($result = drupal_process_form($form_id, $form)) {
00479     // successful submit
00480     return $result;
00481   }
00482   $output = drupal_render_form($form_id, $form);
00483   return $output;
00484 }
00485 
00486 /**
00487  * Form definition for the display layout settings editor.
00488  *
00489  * @ingroup forms
00490  * @see panels_edit_layout_settings_form_validate()
00491  * @see panels_edit_layout_settings_form_submit()
00492  */
00493 function panels_edit_layout_settings_form($display, $finish, $destination, $title) {
00494   $layout = panels_get_layout($display->layout);
00495   $form = array();
00496   if (!empty($layout['settings form']) && function_exists($layout['settings form'])) { // TODO doc the ability to do this as part of the API
00497     $form['layout_settings'] = $layout['settings form']($display, $layout, $display->layout_settings);
00498     $form['layout_settings']['#tree'] = TRUE;
00499   }
00500 
00501   if ($title) {
00502     $form['display_title'] = array (
00503       '#type' => 'fieldset',
00504       '#title' => t('Panel Title'),
00505       '#tree' => TRUE,
00506     );
00507 
00508     $form['display_title']['title'] = array(
00509       '#type' => 'textfield',
00510       '#size' => 35,
00511       '#default_value' => $display->title,
00512       '#title' => t('Title'),
00513       '#description' => t('The title of this panel. Your theme will render this text as the main page title when a user views this panel. Note that there are some circumstances in which this title can be overridden elsewhere.'),
00514     );
00515 
00516     $form['display_title']['hide_title'] = array(
00517       '#type' => 'checkbox',
00518       '#title' => t('Hide Title?'),
00519       '#default_value' => $display->hide_title,
00520       '#description' => t('Check this box to hide the main page title for this panel.'),
00521     );
00522 
00523     if (is_string($title)) {
00524       $form['display_title']['title']['#description'] .= t(" If you leave this field blank, then the default title, '@title', will be used instead.", array('@title' => $title));
00525     }
00526   }
00527 
00528   $form += panels_panel_settings($display);
00529 
00530   $form['variables'] = array(
00531     '#type' => 'value',
00532     '#value' => array($display, $finish, $destination, $title),
00533   );
00534 
00535   if (empty($destination)) {
00536     $form['#redirect'] = FALSE;
00537   }
00538 
00539   $form['layout'] = array(
00540     '#type' => 'value',
00541     '#value' => $layout,
00542   );
00543 
00544   // Always show a Save button even if they sent in a Next or something similar
00545   // button.
00546   if ($finish !== t('Save')) {
00547     $form['save'] = array(
00548       '#type' => 'submit',
00549       '#value' => t('Save'),
00550     );
00551   }
00552 
00553   $form['submit'] = array(
00554     '#type' => 'submit',
00555     '#value' => $finish,
00556   );
00557 
00558 
00559   return $form;
00560 }
00561 
00562 function panels_edit_layout_settings_form_validate($form_id, $form_values, $form) {
00563   list($display, $finish, $destination) = $form_values['variables'];
00564   panels_panel_settings_validate($form_id, $form_values, $form);
00565   $layout = $form_values['layout'];
00566   if (!empty($layout['settings validate']) && function_exists($layout['settings validate'])) {
00567     $layout['settings validate']($form_values['layout_settings'], $form['layout_settings'], $display, $layout, $display->layout_settings);
00568   }
00569 }
00570 
00571 function panels_edit_layout_settings_form_submit($form_id, $form_values) {
00572   list($display, $finish, $destination, $title) = $form_values['variables'];
00573   panels_panel_settings_submit($form_id, $form_values);
00574 
00575   $layout = $form_values['layout'];
00576   if (!empty($layout['settings submit']) && function_exists($layout['settings submit'])) {
00577     $layout['settings submit']($form_values['layout_settings'], $display, $layout, $display->layout_settings);
00578   }
00579 
00580   if (isset($form_values['display_title']['title'])) {
00581     $display->title = $form_values['display_title']['title'];
00582     $display->hide_title = $form_values['display_title']['hide_title'];
00583   }
00584 
00585   if ($form_values['op'] == $finish || $form_values['op'] == t('Save')) {
00586     $display->layout_settings = $form_values['layout_settings'];
00587     $display->panel_settings = $form_values['panel_settings'];
00588 
00589     panels_save_display($display);
00590     drupal_set_message("Your layout settings have been saved.");
00591     if ($form_values['op'] != $finish) {
00592       // This forces us to come back here if they hit Save.
00593       $_REQUEST['destination'] = $_GET['q'];
00594     }
00595     if (empty($destination)) {
00596       return $display;
00597     }
00598     return $destination;
00599   }
00600 }
00601 
00602 /**
00603  * Display the edit form for a pane.
00604  *
00605  * @param $pane
00606  *   The pane to edit.
00607  * @param $parents
00608  *   The form api #parents array that this subform will live in.
00609  */
00610 function panels_get_pane_edit_form($pane, $contexts, $parents) {
00611   return panels_ct_get_edit_form($pane->type, $pane->subtype, $contexts, $pane->configuration, $parents);
00612 }
00613 
00614 /**
00615  * Render a single pane in the edit environment.
00616  *
00617  * @param $pane
00618  *   The pane to render.
00619  * @param $left_buttons
00620  *   Buttons that go on the left side of the pane.
00621  * @param $buttons
00622  *   Buttons that go on the right side of the pane.
00623  * @param $skin
00624  *   If true, provide the outside div. Used to provide an easy way to get
00625  *   just the innards for ajax replacement
00626  */
00627 // TODO check and see if $skin is ever FALSE; pane show/hide setting is dependent on it being TRUE. can't imagine it could be...
00628 function panels_show_pane($display, $pane, $left_buttons, $buttons, $skin = TRUE) {
00629   $content_type = panels_get_content_type($pane->type);
00630   $block = new stdClass();
00631   if (empty($content_type)) {
00632     $block->title = '<em>' . t('Missing content type') . '</em>';
00633     $block->content = t('This pane\'s content type is either missing or has been deleted. This pane will not render.');
00634   }
00635   elseif (function_exists($content_type['editor render callback'])) {
00636     $block = $content_type['editor render callback']($display, $pane);
00637   }
00638   else {
00639     $block = _panels_render_preview_pane_disabled($pane, $display->context);
00640   }
00641 
00642   // This is just used for the title bar of the pane, not the content itself.
00643   // If we know the content type, use the appropriate title for that type,
00644   // otherwise, set the title using the content itself.
00645   $title = !empty($content_type) ? panels_get_pane_title($pane, $display->context) : $block->title;
00646   $output = theme('panels_pane_dnd', $block, $pane->pid, $title, $left_buttons, $buttons);
00647   if ($skin) {
00648     $class = 'panel-pane' . ($pane->shown ? '' : ' hidden-pane');
00649     $output = '<div class="' . $class . '" id="panel-pane-' . $pane->pid . '">' . $output . '</div>';
00650   }
00651   return $output;
00652 }
00653 
00654 /**
00655  * Provide filler content for dynamic pane previews in the editor, as they're just a
00656  * bad idea to have anyway, and can also cause infinite recursion loops that render the
00657  * editor inaccessible in some cases.
00658  *
00659  */
00660 function _panels_render_preview_pane_disabled($pane, $context) {
00661   $block = new stdClass();
00662   $block->title   = panels_get_pane_title($pane, $context);
00663   $block->content = '<em>' . t("Dynamic content previews have been disabled to improve performance and stability for this editing screen.") . '</em>';
00664   return $block;
00665 }
00666 
00667 /**
00668  * Entry point into all ajax operations.
00669  *
00670  * @param string $op
00671  *  The name of the edit operation being performed.
00672  * @param integer $did
00673  *  The id of the $display object being edited (if any).
00674  * @param integer $pid
00675  *  The id of the pane object being edited (if any).
00676  */
00677 // TODO deprecated. should be able to remove it.
00678 function panels_ajax($op = NULL, $did = NULL, $pid = NULL) {
00679   switch ($op) {
00680     case 'submit-form':
00681       if ((is_numeric($did) || $did == 'new') && $cache = panels_cache_get($did)) {
00682         $output = panels_edit_submit_subform($cache->display);
00683       }
00684       break;
00685 
00686     default:
00687   }
00688 
00689   panels_ajax_render($output);
00690 }
00691 
00692 /**
00693  * Entry point for AJAX: 'Add Content' modal form, from which the user selects the
00694  * type of pane to add.
00695  *
00696  * @ingroup PanelsAjax
00697  *
00698  * @param int $did
00699  *  The display id of the $display object currently being edited.
00700  * @param string $panel_id
00701  *  A string with the name of the panel region to which the selected
00702  *  pane type will be added.
00703  */
00704 function panels_ajax_add_content($did = NULL, $panel_id = NULL) {
00705   $output = new stdClass();
00706   if ((is_numeric($did) || $did == 'new') && $cache = panels_cache_get($did)) {
00707     $display = $cache->display;
00708     $layout = panels_get_layout($display->layout);
00709     $layout_panels = panels_get_panels($layout, $display);
00710 
00711     if ($layout && array_key_exists($panel_id, $layout_panels)) {
00712       $output->output = panels_add_content($cache, $panel_id);
00713       $output->type   = 'display';
00714       $output->title  = t('Add content to !s', array('!s' => $layout_panels[$panel_id]));
00715     }
00716   }
00717   panels_ajax_render($output);
00718 }
00719 
00720 /**
00721  * @ingroup PanelsAjax
00722  */
00723 function panels_add_content($cache, $panel_id) {
00724   $return = new stdClass();
00725   $return->type  = 'display';
00726   $return->title = t('Choose type');
00727   // TODO get rid of this deprecated method
00728   panels_set('return', $return);
00729 
00730   if (!isset($cache->content_types)) {
00731     $cache->content_types = panels_get_available_content_types();
00732   }
00733 
00734   $weights    = array(t('Contributed modules') => 0);
00735   $categories = array();
00736   $titles     = array();
00737 
00738   foreach ($cache->content_types as $type_name => $subtypes) {
00739     if (is_array($subtypes)) {
00740       foreach ($subtypes as $subtype_name => $subtype_info) {
00741         $title = filter_xss_admin($subtype_info['title']);
00742         $description = isset($subtype_info['description']) ? $subtype_info['description'] : $title;
00743 
00744         if (isset($subtype_info['icon'])) {
00745           $icon = $subtype_info['icon'];
00746           $path = isset($subtype_info['path']) ? $subtype_info['path'] : panels_get_path("content_types/$type_name");
00747         }
00748         else {
00749           $icon = 'no-icon.png';
00750           $path = panels_get_path('images');
00751         }
00752 
00753         if (isset($subtype_info['category'])) {
00754           if (is_array($subtype_info['category'])) {
00755             list($category, $weight) = $subtype_info['category'];
00756             $weights[$category] = $weight;
00757           }
00758           else {
00759             $category = $subtype_info['category'];
00760             if (!isset($weights['category'])) {
00761               $weights[$category] = 0;
00762             }
00763           }
00764         }
00765         else {
00766           $category = t('Contrib modules');
00767         }
00768 
00769         $output = '<div class="content-type-button clear-block">';
00770         $link_text = theme('image', $path . '/' . $icon, $description, $description);
00771         $output .= l($link_text, 'javascript: void()', array('class' => 'panels-modal-add-config', 'id' => $type_name . '-' . $panel_id . '-' . $subtype_name), NULL, NULL, NULL, TRUE);
00772         $output .= "<div>" . l($title, 'javascript: void()', array('class' => 'panels-modal-add-config', 'id' => $type_name . '-' . $panel_id . '-' . $subtype_name), NULL, NULL, NULL, TRUE) . "</div>";
00773         $output .= '</div>';
00774         if (!isset($categories[$category])) {
00775           $categories[$category] = array();
00776           $titles[$category] = array();
00777         }
00778 
00779         $categories[$category][] = $output;
00780         $titles[$category][] = $title;
00781       }
00782     }
00783   }
00784   if (!$categories) {
00785     $output = t('There are no content types you may add to this display.');
00786   }
00787   else {
00788     asort($weights);
00789     $output = '';
00790 
00791     $columns = 3;
00792     foreach (range(1, $columns) as $column) {
00793       $col[$column] = '';
00794       $size[$column] = 0;
00795     }
00796 
00797     foreach ($weights as $category => $weight) {
00798       $which = 1; // default;
00799       $count = count($titles[$category]) + 3;
00800       // Determine which column to use by seeing which column has the most
00801       // free space. This algorithm favors left.
00802       foreach (range($columns, 2) as $column) {
00803         if ($size[$column - 1] - $size[$column] > $count / 2) {
00804           $which = $column;
00805           break;
00806         }
00807       }
00808 
00809       $col[$which] .= '<div class="panels-section">';
00810       $col[$which] .= '<h3 class="panels-section-title">' . $category . '</h3>';
00811       $col[$which] .= '<div class="panels-section-decorator"></div>';
00812       $col[$which] .= '<div class="panels-section-content">';
00813       if (is_array($titles[$category])) {
00814         natcasesort($titles[$category]);
00815         foreach ($titles[$category] as $id => $title) {
00816           $col[$which] .= $categories[$category][$id];
00817         }
00818       }
00819       $col[$which] .= '</div>';
00820       $col[$which] .= '</div>';
00821       $size[$which] += $count; // add 3 to account for title.
00822     }
00823 
00824     foreach ($col as $column) {
00825       $output .= '<div class="panels-section-column">' . $column . '</div>';
00826     }
00827   }
00828   return $output;
00829 }
00830 
00831 /**
00832  * Entry point for AJAX: toggle pane show/hide status.
00833  *
00834  * @ingroup PanelsAjax
00835  *
00836  * @param int $did
00837  *  The display id for the display object currently being edited. Errors out silently if absent.
00838  * @param int $pid
00839  *  The pane id for the pane object whose show/hide state we're toggling.
00840  * @param string $op
00841  *  The operation - showing or hiding - that this should perform. This could be calculated from
00842  *  cached values, but given that this is a toggle button and people may click it too fast,
00843  *  it's better to leave the decision on which $op to use up to the js than to calculate it here.
00844  */
00845 function panels_ajax_toggle_shown($did = NULL, $pid = NULL, $op = NULL) {
00846   if ((is_numeric($did) || $did == 'new') && $cache = panels_cache_get($did)) {
00847     $ajax_vars = new stdClass();
00848     list($ajax_vars->type, $ajax_vars->id, $ajax_vars->old_op) = array('toggle-shown', $pid, drupal_strtolower($op));
00849 
00850     if ($op == 'Show') {
00851       list($cache->display->content[$pid]->shown, $ajax_vars->output, $ajax_vars->new_op) = array(1, 'Hide', 'hide');
00852     }
00853     elseif ($op == 'Hide') {
00854       list($cache->display->content[$pid]->shown, $ajax_vars->output, $ajax_vars->new_op) = array(0, 'Show', 'show');
00855     }
00856     else {
00857       // bad args, error out.
00858       panels_ajax_render();
00859     }
00860 
00861     panels_cache_set($cache->display->did, $cache);
00862     panels_ajax_render($ajax_vars);
00863   }
00864   panels_ajax_render();
00865 }
00866 
00867 /**
00868  * Entry point for AJAX: Add pane configuration.
00869  *
00870  * After updating the $cache data and equipping a new $pane object with basic values,
00871  * the general-purpose ajax form handler, panels_ajax_form(), is called and pushes the
00872  * configuration form to the screen.
00873  *
00874  * Once form submission is completed, data is pushed back into js by panels_ajax_render().
00875  *
00876  * @ingroup PanelsAjax
00877  *
00878  * @param int $did
00879  *  The display id for the display object currently being edited. Errors out silently if absent.
00880  * @param string $pane_info
00881  *  A string generated by the following code in panels_add_content(): \n
00882  *  @code
00883  *  $output .= l($link_text, 'javascript: void()', array('class' => 'panels-modal-add-config', 'id' => $type_name . '-' . $panel_id . '-' . $subtype_name), NULL, NULL, NULL, TRUE);
00884  *  @endcode \n
00885  *  $type_name contains the name of the content type, $panel_id the name of the panel region
00886  *  to which the pane will be added, and $subtype_name is the name of the content subtype.
00887  *
00888  * @see panels_content_config_form()
00889  */
00890 function panels_ajax_add_config($did = NULL, $pane_info = NULL) {
00891   if ((is_numeric($did) || $did == 'new') && $cache = panels_cache_get($did)) {
00892     if (!isset($_POST['form_id'])) {
00893       $pid = $cache->display->next_new_pid();
00894       $pane = new stdClass();
00895       $pane->pid = "new-$pid";
00896       // Ensure there's no data relics.
00897       unset($cache->content_config[$pane->pid], $cache->pane);
00898       $cc = &$cache->content_config[$pane->pid];
00899 
00900       list($cc['content_type'], $cc['panel_id'], $cc['content_subtype']) = explode('-', $pane_info, 3);
00901       list($pane->type, $pane->subtype, $pane->configuration, $pane->access) = array($cc['content_type'], $cc['content_subtype'], array(), array());
00902       _panels_ajax_ct_preconfigure($cache, $pane);
00903       $cache->pane = drupal_clone($pane);
00904       panels_cache_set($did, $cache);
00905     }
00906     else {
00907       // Not the render passthrough, so the above data has been cached; we retrieve $pane from $cache.
00908       $pane = $cache->pane;
00909       unset($cache->pane);
00910     }
00911 
00912     $ajax_vars = panels_ajax_form('panels_content_config_form',
00913       t('Configure !subtype_title', array('!subtype_title' => $cache->content_config[$pane->pid]['ct_data']['subtype']['title'])),
00914       url($_GET['q'], NULL, NULL, TRUE), $cache, $pane, TRUE
00915     );
00916     panels_ajax_render($ajax_vars);
00917   }
00918   panels_ajax_render();
00919 }
00920 
00921 /**
00922  * Entry point for AJAX: Edit pane configuration.
00923  *
00924  * @ingroup PanelsAjax
00925  *
00926  * Prepares the display $cache and a pre-existing $pane so that the pane configuration
00927  * form for the $pane can be rendered.
00928  *
00929  * Once form submission is completed, data is pushed back into js by panels_ajax_render().
00930  *
00931  * @param int $did
00932  *  The display id of the display object currently being edited. Errors out silently if absent.
00933  * @param
00934  *  The pane id of the pane object whose configuration form we're calling up to edit.
00935  *
00936  * @see panels_content_config_form()
00937  */
00938 function panels_ajax_configure($did = NULL, $pid = NULL) {
00939   if ((is_numeric($did) || $did == 'new') && $cache = panels_cache_get($did)) {
00940     if (isset($cache->display->content[$pid]) && $pane = $cache->display->content[$pid]) {
00941       // Only perform on a form rendering passthrough and if the data hasn't already been built.
00942       if (!isset($_POST['form_id']) && empty($cc['built'])) {
00943         $cc = &$cache->content_config[$pane->pid];
00944         if (!isset($cc)) {
00945           list($cc['content_type'], $cc['content_subtype']) = array($pane->type, $pane->subtype);
00946           _panels_ajax_ct_preconfigure($cache, $pane);
00947           panels_cache_set($did, $cache);
00948         }
00949       }
00950 
00951       $ajax_vars = panels_ajax_form('panels_content_config_form',
00952         t('Configure !subtype_title', array('!subtype_title' => $cache->content_config[$pane->pid]['ct_data']['subtype']['title'])),
00953         url($_GET['q'], NULL, NULL, TRUE), $cache, $pane
00954       );
00955       panels_ajax_render($ajax_vars);
00956     }
00957   }
00958   panels_ajax_render();
00959 }
00960 
00961 /**
00962  * Helper function for ajax pane type editing callbacks. When needed, preps
00963  * the cached $display object with relevant data from the content type.
00964  *
00965  * @ingroup PanelsAjax
00966  *
00967  * @param array $cache
00968  *  The loaded $cache object containing all the current $display editing data.
00969  * @param object $pane
00970  *  The $pane object this ajax callback intends to operate on.
00971  *
00972  * @see panels_ajax_configure()
00973  * @see panels_ajax_add_config()
00974  */
00975 function _panels_ajax_ct_preconfigure(&$cache, &$pane) {
00976   $cc = &$cache->content_config[$pane->pid];
00977   // indicates that the data for this pane has been built for this round of edits and need not be rebuilt
00978   $cc['built'] = TRUE;
00979   $subtype = $cc['ct_data']['subtype'] = $cache->content_types[$pane->type][$pane->subtype];
00980   $type = $cc['ct_data']['type'] = panels_get_content_type($pane->type);
00981 
00982   $cc['ignore_roles'] = !$type['role-based access'];
00983 
00984   if (panels_plugin_get_function('content_types', $type, 'visibility control')) {
00985     $cc['visibility_controller'] = $type['visibility control'];
00986     // defaults to NOT using the built-in pane access system if the ct defines a visibility callback
00987     $cc['ignore_roles'] = TRUE;
00988     if (isset($type['roles and visibility']) && $type['roles and visibility'] === TRUE) {
00989       $cc['ignore_roles'] = FALSE;
00990     }
00991   }
00992 
00993   if (panels_plugin_get_function('content_types', $type, 'form control')) {
00994     $cc['form_controller'] = $type['form control'];
00995   }
00996 }
00997 
00998 /**
00999  * Master FAPI definition for all pane add/edit configuration forms.
01000  *
01001  * @ingroup PanelsAjax
01002  *
01003  * @param object $cache
01004  *  The $cache object for the panels $display currently being edited.
01005  * @param object $pane
01006  *  The $pane object currently being added/edited.
01007  * @param bool $add
01008  *  A boolean indicating whether we are adding a new pane ($add === TRUE)
01009  *  operation in this operation, or editing an existing pane ($add === FALSE).
01010  *
01011  * @return array $form
01012  *  A structured FAPI form definition, having been passed through all the appropriate
01013  *  content-type specific callbacks.
01014  */
01015 function panels_content_config_form($cache, $pane, $add = FALSE) {
01016   $op = $add ? 'add' : 'edit';
01017   // for brevity and readability.
01018   $cc = $cache->content_config[$pane->pid];
01019 
01020   $form['start_form'] = array('#value' => '<div class="modal-form">');
01021 
01022   $form['configuration'] = panels_ct_conf_form($cc['ct_data'], $cache->display->context, $pane->configuration);
01023   if (is_array($form_additions = panels_ct_pane_config_form($pane, $cache->display->context, array('configuration'), $op))) {
01024     $form['configuration'] += $form_additions;
01025   }
01026   $form['configuration']['#tree'] = TRUE;
01027 
01028   if (!$cc['ignore_roles']) {
01029     if (user_access('administer pane access')) {
01030       $rids = array();
01031       $result = db_query("SELECT r.rid, r.name FROM {role} r ORDER BY r.name");
01032       while ($obj = db_fetch_object($result)) {
01033         $rids[$obj->rid] = $obj->name;
01034       }
01035 
01036       $form['access'] = array(
01037         '#type' => 'checkboxes',
01038         '#title' => t('Access'),
01039         '#default_value' => $add ? array() : $pane->access,
01040         '#options' => $rids,
01041         '#description' => t('Only the checked roles will be able to see this pane; if no roles are checked, access will not be restricted.'),
01042       );
01043     }
01044     else {
01045       $form['access'] = array(
01046         '#type' => 'value',
01047         '#value' => isset($pane->access) ? $pane->access : array(),
01048       );
01049     }
01050   }
01051 
01052   if (isset($cc['visibility_controller'])) {
01053     $form['visibility'] = $cc['visibility_controller']($cache->display->context, $pane->subtype, $pane->configuration, $add);
01054   }
01055 
01056   $form['end_form'] = array('#value' => '</div>');
01057 
01058   $form['next'] = array(
01059     '#type' => 'submit',
01060     '#value' => $add ? t('Add pane') : t('Save'),
01061   );
01062 
01063   $form['vars'] = array('#type' => 'value', '#value' => array($cache, $pane, $add, $op));
01064 
01065   // Allows content types that define this callback to have full control over the pane config form.
01066   if (isset($cc['form_controller'])) {
01067     call_user_func_array($cc['form_controller'], array(&$form, &$cache->content_config[$pane->pid], &$cache->display, $add));
01068     // Only set the cache with any new vars on the render passthrough; setting
01069     // it again could, depending on the changes in the plugin function, cause
01070     // serious data consistency problems.
01071     if (!isset($_POST['form_id'])) {
01072       panels_cache_set($cache->display->did, $cache);
01073     }
01074   }
01075   return $form;
01076 }
01077 
01078 /**
01079  * FAPI validator for panels_content_config_form().
01080  *
01081  * Call any validation functions defined by the content type.
01082  *
01083  */
01084 function panels_content_config_form_validate($form_id, $form_values, $form) {
01085   list($cache, $pane, $add, $op) = $form_values['vars'];
01086   panels_ct_pane_validate_form($pane->type, $form['configuration'], $form_values['configuration'], $op);
01087 }
01088 
01089 /**
01090  * FAPI submit handler for panels_content_config_form().
01091  *
01092  * @ingroup PanelsAjax
01093  *
01094  * Call any submit handlers defined by the content type, update
01095  * the $cache object with the relevant data, save $cache to the
01096  * object_cache table, and return data for ajax updates.
01097  *
01098  * @return object $ajax_vars
01099  *  Variables to be passed to the ajax handler so that the overall edit form can
01100  *  be updated as needed.
01101  */
01102 function panels_content_config_form_submit($form_id, $form_values) {
01103   list($cache, $pane, $add, $op) = $form_values['vars'];
01104   // Start by saving all initial $pane values into the array of pane data in $display->content.
01105   $cache->display->content[$pane->pid] = $pane;
01106   // Call the submit handler provided by the pane type, if any.
01107   panels_ct_pane_submit_form($pane->type, $form_values['configuration'], $op);
01108 
01109   if (isset($form_values['visibility'])) {
01110     if ($visibility_submit = panels_plugin_get_function('content_types', $cache->content_config[$pane->pid]['ct_data']['type'], 'visibility submit')) {
01111       // Use call_user_func_array() in order to ensure that all these values can only be passed by value.
01112       $cache->display->content[$pane->pid]->visibility = call_user_func_array($visibility_submit,
01113         array($form_values['visibility'], $add, $cache->display->content[$pane->pid], $cache->display));
01114     }
01115     else {
01116       // If no visibility submit callback is defined, fall back to the default storage behavior. Should be
01117       // adequate for the vast majority of use cases, so most client modules won't need to define callbacks.
01118       $cache->display->content[$pane->pid]->visibility = is_array($form_values['visibility']) ? array_keys(array_filter($form_values['visibility'])) : $form_values['visibility'];
01119     }
01120   }
01121   else {
01122     $cache->display->content[$pane->pid]->visibility = '';
01123   }
01124 
01125   if (isset($form_values['access'])) {
01126     $cache->display->content[$pane->pid]->access = array_keys(array_filter($form_values['access']));
01127   }
01128   else {
01129     $cache->display->content[$pane->pid]->access = array();
01130   }
01131 
01132   $cache->display->content[$pane->pid]->configuration = $form_values['configuration'];
01133 
01134   // Call submit handlers specific to the $op ('add' or 'edit').
01135   $ajax_vars = call_user_func_array("panels_content_config_" . $op . "_form_submit", array($form_values, &$cache, $pane));
01136   $ajax_vars->id = $pane->pid;
01137   panels_cache_set($cache->display->did, $cache);
01138   return $ajax_vars;
01139 }
01140 
01141 function panels_content_config_add_form_submit($form_values, $cache, $pane) {
01142   $ajax_vars = new stdClass();
01143   $ajax_vars->type   = 'add';
01144   $ajax_vars->region = $cache->content_config[$pane->pid]['panel_id'];
01145 
01146   $cache->display->panels[$cache->content_config[$pane->pid]['panel_id']][] = $pane->pid;
01147   $cache->display->content[$pane->pid]->shown = TRUE;
01148 
01149   // we need to fake the buttons a little.
01150   // new panes are shown by default
01151   $buttons['configure'] = panels_add_button('icon-configure.png', t('Configure'), t('Configure this pane'), 'pane-configure');
01152   $buttons['configure']['#parents'] = array('button', $pane->pid, 'configure');
01153 
01154   if (panels_get_caches() && user_access('use panels caching features')) {
01155     $buttons['cache'] = panels_add_button('icon-cache.png', t('Caching'), t('Control caching'), 'pane-cache');
01156     $buttons['cache']['#parents'] = array('button', $pane->pid, 'cache');
01157   }
01158 
01159   $buttons['show_hide'] = panels_add_button('icon-hidepane.png', t('Show/Hide Toggle'), t('Hide this pane'), 'pane-toggle-shown');
01160   $buttons['show_hide']['#parents'] = array('button', $pane->pid, 'show_hide');
01161 
01162   $buttons['delete'] = panels_add_button('icon-delete.png', t('Delete'), t('Remove this pane'), 'pane-delete');
01163   $buttons['delete']['#parents'] = array('button', $pane->pid, 'delete');
01164 
01165   $buttons = form_builder('dummy', $buttons);
01166 
01167   // Render the new pane for the javascript.
01168   $ajax_vars->output = panels_show_pane($cache->display, $cache->display->content[$pane->pid], NULL, drupal_render($buttons));
01169   return $ajax_vars;
01170 }
01171 
01172 /**
01173  * @ingroup PanelsAjax
01174  */
01175 function panels_content_config_edit_form_submit($form_values, $cache, $pane) {
01176   // If this content type defines its own 'editor render callback', we need to
01177   // invoke that again, since we're not doing a full panels_show_pane().
01178   $content_type = $cache->content_config[$pane->pid]['ct_data']['type'];
01179   if (function_exists($content_type['editor render callback'])) {
01180     $block = $content_type['editor render callback']($cache->display, $pane);
01181   }
01182   else {
01183     $block = _panels_render_preview_pane_disabled($pane, $cache->display->context);
01184   }
01185   $ajax_vars = new stdClass();
01186   $ajax_vars->type   = 'replace';
01187   $ajax_vars->output = theme('panels_pane_collapsible', $block, $cache->display);
01188   return $ajax_vars;
01189 }
01190 
01191 /**
01192  * Entry point for AJAX modal: configure pane
01193  * @ingroup PanelsAjax
01194  */
01195 function panels_ajax_cache($did = NULL, $pid = NULL) {
01196   if (!((is_numeric($did) || $did == 'new') && $cache = panels_cache_get($did))) {
01197     panels_ajax_render();
01198   }
01199 
01200   // First, check to see if this is a form being submitted and, if it is, which
01201   // one, because we can have two forms here.
01202   if (!empty($_POST) && !empty($_POST['form_id']) && $_POST['form_id'] == 'panels_edit_cache_settings_form') {
01203     return panels_ajax_cache_settings($cache, $pid);
01204   }
01205 
01206   $method = panels_ajax_form('panels_edit_cache_method_form',
01207     t('Select cache method'), url($_GET['q'], NULL, NULL, TRUE),
01208     $cache->display, $pid
01209   );
01210   return panels_ajax_cache_settings($cache, $pid, $method);
01211 }
01212 
01213 /**
01214  * Choose cache method form
01215  * @ingroup PanelsAjax
01216  */
01217 function panels_edit_cache_method_form($display, $pid) {
01218   $conf = $pid ? $display->content[$pid]->cache : $display->cache;
01219 
01220   // Set to 0 to ensure we get a selected radio.
01221   if (!isset($conf['method'])) {
01222     $conf['method'] = 0;
01223   }
01224 
01225   $caches = panels_get_caches();
01226   if (empty($caches)) {
01227     $form['markup'] = array('#value' => t('No caching options are available at this time. Please enable a panels caching module in order to use caching options.'));
01228     return $form;
01229   }
01230 
01231   $options[0] = t('No caching');
01232   foreach ($caches as $cache => $info) {
01233     $options[$cache] = check_plain($info['title']);
01234   }
01235 
01236   $form['method'] = array(
01237     '#prefix' => '<div class="no-float">',
01238     '#suffix' => '</div>',
01239     '#type' => 'radios',
01240     '#title' => t('Method'),
01241     '#options' => $options,
01242     '#default_value' => $conf['method'],
01243   );
01244 
01245   $form['submit'] = array(
01246     '#type' => 'submit',
01247     '#value' => t('Next'),
01248   );
01249   return $form;
01250 }
01251 
01252 /**
01253  * Submit callback for panels_edit_cache_method_form.
01254  *
01255  * All this needs to do is return the method.
01256  * @ingroup PanelsAjax
01257  */
01258 function panels_edit_cache_method_form_submit($form_id, $form_values) {
01259   return $form_values['method'];
01260 }
01261 
01262 /**
01263  * Handle the cache settings form
01264  * @ingroup PanelsAjax
01265  */
01266 function panels_ajax_cache_settings($cache, $pid, $method = NULL) {
01267   if (empty($method) && isset($_POST['method'])) {
01268     // Retrieve the method from the form.
01269     $method = $_POST['method'];
01270   }
01271 
01272   if (empty($method) || !($function = panels_plugin_get_function('cache', $method, 'settings form'))) {
01273     panels_ajax_set_cache_data($cache->display, $pid, 0);
01274   }
01275   else {
01276     $cache->display = panels_ajax_form('panels_edit_cache_settings_form',
01277       t('Configure cache settings'), url($_GET['q'], NULL, NULL, TRUE),
01278       $cache->display, $pid, $method, $function
01279     );
01280   }
01281 
01282   panels_cache_set($cache->display->did, $cache);
01283 
01284   if ($pid) {
01285     $ajax_vars = new stdClass();
01286     list($ajax_vars->id, $ajax_vars->output, $ajax_vars->type) = array($pid, 'Changed', 'dismiss-changed');
01287     panels_ajax_render($ajax_vars);
01288   }
01289   else {
01290     panels_ajax_render('dismiss');
01291   }
01292 }
01293 
01294 /**
01295  * Set the cache method and associated settings on the display.
01296  * @ingroup PanelsAjax
01297  */
01298 function panels_ajax_set_cache_data(&$display, $pid, $method, $settings = array()) {
01299   if ($pid) {
01300     $conf = &$display->content[$pid]->cache;
01301   }
01302   else {
01303     $conf = &$display->cache;
01304   }
01305 
01306   $conf['method'] = $method;
01307   $conf['settings'] = $settings;
01308 }
01309 
01310 /**
01311  * Cache settings form
01312  * @ingroup PanelsAjax
01313  */
01314 function panels_edit_cache_settings_form($display, $pid, $method, $settings_function) {
01315   $conf = $pid ? $display->content[$pid]->cache : $display->cache;
01316   $info = panels_get_cache($method);
01317 
01318   $form['description'] = array(
01319     '#prefix' => '<div class="description">',
01320     '#suffix' => '</div>',
01321     '#value' => check_plain($info['description']),
01322   );
01323   $form['settings'] = $settings_function($conf['settings'], $display, $pid);
01324   $form['settings']['#tree'] = TRUE;
01325 
01326   $form['method'] = array(
01327     '#type' => 'hidden',
01328     '#value' => $method,
01329   );
01330 
01331   $form['display'] = array(
01332     '#type' => 'value',
01333     '#value' => $display,
01334   );
01335 
01336   $form['pid'] = array(
01337     '#type' => 'value',
01338     '#value' => $pid,
01339   );
01340 
01341   $form['submit'] = array(
01342     '#type' => 'submit',
01343     '#value' => t('Save'),
01344   );
01345   return $form;
01346 }
01347 
01348 /**
01349  * Validate cache settings.
01350  */
01351 function panels_edit_cache_settings_form_validate($form_id, $form_values, $form) {
01352   if ($function = panels_plugin_get_function('cache', $form_values['method'], 'settings form validate')) {
01353     $function($form, $form_values['settings']);
01354   }
01355 }
01356 
01357 /**
01358  * Allows panel styles to validate their style settings.
01359  * @ingroup PanelsAjax
01360  */
01361 function panels_edit_cache_settings_form_submit($form_id, $form_values) {
01362   if ($function = panels_plugin_get_function('cache', $form_values['method'], 'settings form submit')) {
01363     $function($form_values['settings']);
01364   }
01365 
01366   // Identify which configuration we're setting
01367   $pid = $form_values['pid'];
01368   $display = $form_values['display'];
01369 
01370   panels_ajax_set_cache_data($display, $pid, $form_values['method'], $form_values['settings']);
01371   return $display;
01372 }
01373 
01374 /**
01375  * @ingroup PanelsAjax
01376  */
01377 function panels_edit_submit_subform($display) {
01378   // Check forms to make sure only valid forms can be rendered this way.
01379   $valid_forms = array('panels_add_content_config_form', 'panels_edit_pane_config_form');
01380   $form_id = $_POST['form_id'];
01381   if (!in_array($form_id, $valid_forms)) {
01382     return panels_ajax_render();
01383   }
01384 
01385   $output = drupal_get_form($form_id, $display);
01386 
01387   $next = panels_get('next');
01388 
01389   if ($next) {
01390     $output = drupal_get_form($next['form'], $display, $next['data']);
01391     $return = panels_get('return');
01392     if (!$return->output) {
01393       $return->output = $output;
01394     }
01395   }
01396   else {
01397     if (!($return = panels_get('return'))) {
01398       $return->type = 'display';
01399       $return->output = $output;
01400     }
01401     else if ($return->type == 'display' && !$return->output) {
01402       $return->output = $output;
01403     }
01404   }
01405 
01406   if ($return->type == 'display') {
01407     $return->output = theme('status_messages') . $return->output;
01408   }
01409   return $return;
01410 }
01411 
01412 // ------------------------------------------------------------------
01413 // Panels settings + ajax for modal popup
01414 
01415 /**
01416  * Form to edit panel style settings.
01417  * @ingroup PanelsAjax
01418  */
01419 function panels_panel_settings($display) {
01420   $panel_settings = $display->panel_settings;
01421   $style = panels_get_style((!empty($panel_settings['style'])) ? $panel_settings['style'] : 'default');
01422 
01423   // Let the user choose between panel styles that are available for any
01424   // panels implementation or specifically to this one.
01425   $options = array();
01426   foreach (panels_get_styles() as $name => $properties) {
01427     if (empty($properties['hidden']) && (!empty($properties['render panel']))) {
01428       $options[$name] = $properties['title'];
01429     }
01430   }
01431 
01432   $form = array();
01433 
01434   $form['display'] = array('#type' => 'value', '#value' => $display);
01435 
01436   $form['panel_settings'] = array(
01437     '#type' => 'fieldset',
01438     '#title' => t('Panel settings'),
01439     '#tree' => TRUE,
01440   );
01441 
01442   $form['panel_settings']['start_box'] = array(
01443     '#value' => '<div class="form-item clear-block"><label>' . t('Default panel style') . ':</label>',
01444   );
01445 
01446   $modals = array();
01447   $form['panel_settings']['style'] = array(
01448     '#prefix' => '<div class="panels-style-settings-box">',
01449     '#suffix' => '</div>',
01450     '#type' => 'select',
01451     '#options' => $options,
01452     '#id' => 'panel-settings-style',
01453     '#default_value' => $style['name'],
01454   );
01455 
01456   // Is this form being posted? If so, check cache.
01457   if (!empty($_POST)) {
01458     $style_settings = panels_common_cache_get('style_settings', $display->did);
01459   }
01460   if (!isset($style_settings)) {
01461     $style_settings = !empty($panel_settings['style_settings']) ? $panel_settings['style_settings'] : array();
01462     panels_common_cache_set('style_settings', $display->did, $style_settings);
01463   }
01464 
01465   $form['panel_settings']['style_settings'] = array(
01466     '#type' => 'value',
01467     '#value' => $style_settings,
01468   );
01469   $form['panel_settings']['edit_style'] = array(
01470     '#type' => 'submit',
01471     '#id' => 'panels-style-settings',
01472     '#value' => t('Edit style settings'),
01473   );
01474 
01475   // Set up the AJAX settings for the modal.
01476   $modals['#panels-style-settings'] = array(url('panels/ajax/panel_settings/' . $display->did . '/default', NULL, NULL, TRUE), '#panel-settings-style');
01477 
01478   $form['panel_settings']['end_box'] = array(
01479     '#value' => '</div>',
01480   );
01481 
01482   $form['panel_settings']['individual'] = array(
01483     '#type' => 'checkbox',
01484     '#title' => t('Per panel settings'),
01485     '#id' => 'panel-settings-individual',
01486     '#description' => t('If this is checked, each region in the display can have its own style.'),
01487     '#default_value' => $panel_settings['individual'],
01488   );
01489 
01490   $layout_options = array_merge(array('-1' => t('Use the default panel style')), $options);
01491   $layout         = panels_get_layout($display->layout);
01492   $layout_panels  = panels_get_panels($layout, $display);
01493 
01494   $checkboxes = array();
01495   foreach ($layout_panels as $id => $name) {
01496     $form['panel_settings']['panel'][$id]['start_box'] = array(
01497       '#value' => '<div class="form-item clear-block"><label>' . $name . ':</label>',
01498     );
01499     $form['panel_settings']['panel'][$id]['style'] = array(
01500       '#prefix' => '<div class="panels-style-settings-box">',
01501       '#suffix' => '</div>',
01502       '#type' => 'select',
01503       '#options' => $layout_options,
01504       '#id' => 'panel-settings-style-' . $id,
01505       '#default_value' => $display->panel_settings['panel'][$id]['style'],
01506     );
01507     $checkboxes[] = '#panel-settings-style-' . $id;
01508 
01509     $form['panel_settings']['panel'][$id]['edit_style'] = array(
01510       '#type' => 'submit',
01511       '#id' => 'panels-style-settings-' . $id,
01512       '#attributes' => array('class' => 'panels-style-settings'),
01513       '#value' => t('Edit style settings'),
01514     );
01515     $checkboxes[] = '#panels-style-settings-' . $id;
01516 
01517     // Set up the AJAX settings for the modal.
01518     $modals['#panels-style-settings-' . $id ] = array(url('panels/ajax/panel_settings/' . $display->did . '/' . $id, NULL, NULL, TRUE), '#panel-settings-style-' . $id);
01519 
01520     $form['panel_settings']['panel'][$id]['end_box'] = array(
01521       '#value' => '</div>',
01522     );
01523   }
01524 
01525   // while we don't use this directly some of our forms do.
01526   drupal_add_js('misc/collapse.js');
01527   drupal_add_js('misc/autocomplete.js');
01528 
01529   $ajax = array('panels' => array(
01530     'closeText' => t('Close Window'),
01531     'closeImage' => theme('image', panels_get_path('images/icon-delete.png'), t('Close window'), t('Close window')),
01532     'throbber' => theme('image', panels_get_path('images/throbber.gif'), t('Loading...'), t('Loading')),
01533     'checkboxes' => array('#panel-settings-individual' => $checkboxes),
01534     'modals' => $modals,
01535   ));
01536 
01537   $form['panel_settings']['did'] = array(
01538     '#type' => 'value',
01539     '#value' => $display->did,
01540   );
01541 
01542   drupal_add_js(panels_get_path('js/lib/dimensions.js'));
01543   drupal_add_js(panels_get_path('js/lib/mc.js'));
01544   drupal_add_js(panels_get_path('js/lib/form.js'));
01545   drupal_add_js($ajax, 'setting');
01546   drupal_add_js(panels_get_path('js/checkboxes.js'));
01547   drupal_add_js(panels_get_path('js/modal_forms.js'));
01548   drupal_add_css(panels_get_path('css/panels_dnd.css'));
01549 
01550   return $form;
01551 }
01552 
01553 /**
01554  * @} ends PanelsAjax group
01555  */
01556 
01557 function panels_panel_settings_validate($form_id, $form_values, $form) {
01558   $settings = panels_common_cache_get('style_settings', $form_values['panel_settings']['did']);
01559   form_set_value($form['panel_settings']['style_settings'], $settings);
01560 }
01561 
01562 function panels_panel_settings_submit($form_id, $form_values) {
01563   panels_common_cache_clear('style_settings', $form_values['panel_settings']['did']);
01564 }
01565 
01566 /**
01567  * AJAX incoming to deal with the style settings modal
01568  *
01569  * @ingroup PanelsAjax
01570  */
01571 function panels_panel_settings_ajax($did, $panel, $name) {
01572   if ($name == '0') {
01573     panels_ajax_render(t('There are no style settings to edit.'), t('Edit default style settings'));
01574   }
01575 
01576   $style = panels_get_style($name);
01577   $style_settings = panels_common_cache_get('style_settings', $did);
01578   if (!isset($style_settings)) {
01579     panels_ajax_render();
01580   }
01581 
01582   // Render the panels ajax form. This only returns to us on successful
01583   // submit; otherwise the form is rendered for us and nothing else happens.
01584   $style_settings[$panel] = panels_ajax_form('panels_common_style_settings_form',
01585     t('Edit style settings for @style', array('@style' => $style['title'])),
01586     url($_GET['q'], NULL, NULL, TRUE),
01587     $did, $style, $style_settings[$panel]
01588   );
01589 
01590   panels_common_cache_set('style_settings', $did, $style_settings);
01591   panels_ajax_render('dismiss');
01592 }
01593 
01594 /**
01595  * Form for the style settings modal.
01596  *
01597  * @ingroup PanelsAjax
01598  */
01599 function panels_common_style_settings_form($did, $style, $style_settings) {
01600   $form['start_form'] = array('#value' => '<div class="modal-form">');
01601   $form['description'] = array(
01602     '#prefix' => '<div class="description">',
01603     '#suffix' => '</div>',
01604     '#value' => check_plain($style['description']),
01605   );
01606 
01607   if (isset($style['settings form']) && function_exists($style['settings form'])) {
01608     $form['style_settings'] = $style['settings form']($style_settings);
01609     $form['style_settings']['#tree'] = TRUE;
01610   }
01611   else {
01612     $form['markup'] = array(
01613       '#value' => t('This style does not have any settings.'),
01614     );
01615   }
01616   $form['end_form'] = array('#value' => '</div>');
01617 
01618   if (!isset($form['markup'])) {
01619     $form['style'] = array(
01620       '#type' => 'value',
01621       '#value' => $style,
01622     );
01623 
01624     $form['did'] = array(
01625       '#type' => 'value',
01626       '#value' => $did,
01627     );
01628 
01629     $form['next'] = array(
01630       '#type' => 'submit',
01631       '#value' => t('Save'),
01632     );
01633   }
01634 
01635   return $form;
01636 }
01637 
01638 /**
01639  * Allows panel styles to validate their style settings.
01640  */
01641 function panels_common_style_settings_form_validate($form_id, $form_values, $form) {
01642   $style = $form_values['style'];
01643 
01644   if (isset($style['settings form validate']) && function_exists($style['settings form validate'])) {
01645     $style['settings form validate']($form, $form_values['style_settings']);
01646   }
01647 }
01648 
01649 /**
01650  * Allows panel styles to validate their style settings.
01651  */
01652 function panels_common_style_settings_form_submit($form_id, $form_values) {
01653   $style = $form_values['style'];
01654 
01655   if (isset($style['settings form submit']) && function_exists($style['settings form submit'])) {
01656     $style['settings form submit']($form_values['style_settings']);
01657   }
01658 
01659   return $form_values['style_settings'];
01660 }
01661 
01662 /**
01663  * Includes required JavaScript libraries.
01664  */
01665 function _panels_js_files() {
01666   // while we don't use this directly some of our forms do.
01667   drupal_add_js('misc/collapse.js');
01668   drupal_add_js('misc/autocomplete.js');
01669 
01670   drupal_add_js(panels_get_path('js/lib/dimensions.js'));
01671   drupal_add_js(panels_get_path('js/lib/mc.js'));
01672   drupal_add_js(panels_get_path('js/lib/form.js'));
01673   drupal_add_js(array('panelsAjaxURL' => url('panels/ajax', NULL, NULL, TRUE)), 'setting');
01674   drupal_add_js(panels_get_path('js/display_editor.js'));
01675   drupal_add_js(panels_get_path('js/checkboxes.js'));
01676   drupal_add_js(panels_get_path('js/modal_forms.js'));
01677   drupal_add_css(panels_get_path('css/panels_dnd.css'));
01678   drupal_add_css(panels_get_path('css/panels_admin.css'));
01679 }
01680 
01681 // ---------------------------------------------------------------------------
01682 // Panels theming functions
01683 
01684 // @DND
01685 function theme_panels_dnd($content) {
01686   $output = "<div class=\"panels-dnd\" id=\"panels-dnd-main\">$content</div>";
01687   return $output;
01688 }
01689 
01690 // @DND
01691 function theme_panels_panel_dnd($content, $region, $label, $footer) {
01692   return "<div class=\"panels-display\" id=\"panel-pane-$region\">$footer<h2 class=\"label\">$label</h2>$content</div>";
01693 }
01694 
01695 // @DND
01696 function theme_panels_pane_dnd($block, $id, $label, $left_buttons = NULL, $buttons = NULL) {
01697   if (!$block->title) {
01698     $block->title = t('No title');
01699   }
01700   static $count = 0;
01701   $output .= "<div class=\"grabber\">";
01702   if ($buttons) {
01703     $output .= "<span class='buttons'>$buttons</span>";
01704   }
01705   if ($left_buttons) {
01706     $output .= "<span class='left_buttons'>$left_buttons</span>";
01707   }
01708   $output .= "<span class=\"text\">$label</span></div>";
01709   $output .= '<div class="panel-pane-collapsible">';
01710   $output .= theme('panels_pane_collapsible', $block);
01711   $output .= '</div>';
01712   return $output;
01713 }
01714 
01715 // @DND
01716 function theme_panels_pane_collapsible($block) {
01717   $output .= '<h2 class="title">' . $block->title . '</h2>';
01718   $output .= '<div class="content">' . filter_xss_admin($block->content) . '</div>';
01719   return $output;
01720 }
01721 
01722 /**
01723  * This is separate because it must be outside the <form> to work, and
01724  * everything in the form theme is inside the form.
01725  */
01726 // @DND
01727 function theme_panels_hidden() {
01728   $close_text     = t('Close Window');
01729   $close_image    = theme('image', panels_get_path('images/icon-delete.png'), t('Close window'), t('Close window'));
01730   $throbber_image = theme('image', panels_get_path('images/throbber.gif'), t('Loading...'), t('Loading'));
01731   $output         = <<<EOF
01732 <div class="panels-hidden">\n
01733   <div id="panels-modal">\n
01734     <div class="panels-modal-content">\n
01735        <div class="modal-header">\n
01736          <a class="close" href="#">$close_text $close_image</a>\n
01737          <span class="modal-title">&nbsp;</span>\n
01738        </div>\n
01739        <div class="modal-content">\n
01740        </div>\n
01741     </div>\n
01742   </div>\n
01743   <div id="panels-throbber">\n
01744     <div class="panels-throbber-wrapper">
01745       $throbber_image\n
01746     </div>
01747   </div>\n
01748 </div>\n
01749 EOF;
01750 
01751   return $output;
01752 }
01753 

Generated on Thu Feb 9 05:00:14 2012 for Panels 2 by  doxygen 1.5.6