| Commit | Line | Data |
|---|---|---|
| 9f3609c9 EM |
1 | <?php |
| 2 | // $Id$ | |
| 3 | ||
| b76f0bd4 SB |
4 | /** |
| 5 | * @file panels.module | |
| 6 | * | |
| 7 | * Core functionality for the Panels engine. | |
| 8 | */ | |
| 9 | ||
| 40ab7380 | 10 | define('PANELS_REQUIRED_CTOOLS_API', '1.1.1'); |
| ee0e6fa9 | 11 | |
| b76f0bd4 | 12 | /** |
| f2e5a0c5 EM |
13 | * Returns the API version of Panels. This didn't exist in 1. |
| 14 | * | |
| 15 | * @return An array with the major and minor versions | |
| 9f3609c9 | 16 | */ |
| f2e5a0c5 | 17 | function panels_api_version() { |
| 5cf19555 | 18 | return array(3, 0); |
| f2e5a0c5 EM |
19 | } |
| 20 | ||
| 5cf19555 EM |
21 | /** |
| 22 | * Implementation of hook_theme() | |
| 23 | */ | |
| f2e5a0c5 | 24 | function panels_theme() { |
| ee0e6fa9 EM |
25 | // Safety: go away if CTools is not at an appropriate version. |
| 26 | if (!module_invoke('ctools', 'api_version', PANELS_REQUIRED_CTOOLS_API)) { | |
| ab4648f3 EM |
27 | return array(); |
| 28 | } | |
| 29 | ||
| f2e5a0c5 EM |
30 | $theme = array(); |
| 31 | $theme['panels_layout_link'] = array( | |
| 32 | 'arguments' => array('title', 'id', 'image', 'link'), | |
| 33 | ); | |
| 34 | $theme['panels_layout_icon'] = array( | |
| 35 | 'arguments' => array('id', 'image', 'title' => NULL), | |
| 36 | ); | |
| f2e5a0c5 EM |
37 | $theme['panels_edit_display_form'] = array( |
| 38 | 'arguments' => array('form'), | |
| 39 | 'file' => 'includes/display-edit.inc', | |
| 40 | ); | |
| 41 | $theme['panels_edit_layout_form_choose'] = array( | |
| 42 | 'arguments' => array('form'), | |
| 43 | 'file' => 'includes/display-edit.inc', | |
| 44 | ); | |
| f2e5a0c5 EM |
45 | $theme['panels_pane'] = array( |
| 46 | 'arguments' => array('content', 'pane', 'display'), | |
| 6d7f8ba7 | 47 | 'file' => 'includes/display-render.inc', |
| f2e5a0c5 EM |
48 | ); |
| 49 | $theme['panels_common_content_list'] = array( | |
| 50 | 'arguments' => array('display'), | |
| 51 | 'file' => 'includes/common.inc', | |
| 52 | ); | |
| d75b98c7 EM |
53 | $theme['panels_render_display_form'] = array( |
| 54 | 'arguments' => array('form' => NULL), | |
| 55 | ); | |
| f2e5a0c5 | 56 | |
| 287328f3 EM |
57 | $theme['panels_dashboard'] = array( |
| 58 | 'arguments' => array(), | |
| 59 | 'path' => drupal_get_path('module', 'panels') . '/templates', | |
| 60 | 'file' => '../includes/callbacks.inc', | |
| 61 | 'template' => 'panels-dashboard', | |
| 62 | ); | |
| ee0e6fa9 | 63 | |
| f2e5a0c5 EM |
64 | // Register layout and style themes on behalf of all of these items. |
| 65 | panels_load_include('plugins'); | |
| 66 | ||
| 67 | // No need to worry about files; the plugin has to already be loaded for us | |
| 68 | // to even know what the theme function is, so files will be auto included. | |
| 69 | $layouts = panels_get_layouts(); | |
| 70 | foreach ($layouts as $name => $data) { | |
| efcf7fcf EM |
71 | foreach (array('theme', 'admin theme') as $callback) { |
| 72 | if (!empty($data[$callback])) { | |
| 73 | $theme[$data[$callback]] = array( | |
| 74 | 'arguments' => array('css_id' => NULL, 'content' => NULL, 'settings' => NULL, 'display' => NULL), | |
| 75 | 'path' => $data['path'], | |
| 76 | ); | |
| 77 | ||
| 78 | // if no theme function exists, assume template. | |
| 79 | if (!function_exists("theme_$data[theme]")) { | |
| 80 | $theme[$data[$callback]]['template'] = str_replace('_', '-', $data[$callback]); | |
| 81 | $theme[$data[$callback]]['file'] = $data['file']; // for preprocess. | |
| 82 | } | |
| fc8f8fa8 | 83 | } |
| f2e5a0c5 | 84 | } |
| 9f3609c9 | 85 | } |
| f2e5a0c5 EM |
86 | |
| 87 | $styles = panels_get_styles(); | |
| 88 | foreach ($styles as $name => $data) { | |
| 89 | if (!empty($data['render pane'])) { | |
| 90 | $theme[$data['render pane']] = array( | |
| 91 | 'arguments' => array('content' => NULL, 'pane' => NULL, 'display' => NULL), | |
| 92 | ); | |
| 93 | } | |
| 94 | if (!empty($data['render panel'])) { | |
| 95 | $theme[$data['render panel']] = array( | |
| 96 | 'arguments' => array('display' => NULL, 'panel_id' => NULL, 'panes' => NULL, 'settings' => NULL), | |
| 97 | ); | |
| 98 | } | |
| 99 | ||
| efcf7fcf EM |
100 | if (!empty($data['hook theme'])) { |
| 101 | if (is_array($data['hook theme'])) { | |
| 102 | $theme += $data['hook theme']; | |
| 103 | } | |
| 104 | else if (function_exists($data['hook theme'])) { | |
| 105 | $data['hook theme']($theme, $data); | |
| 106 | } | |
| 107 | } | |
| f2e5a0c5 EM |
108 | } |
| 109 | ||
| 110 | return $theme; | |
| 9f3609c9 EM |
111 | } |
| 112 | ||
| 113 | /** | |
| f2e5a0c5 | 114 | * Implementation of hook_menu |
| 9f3609c9 | 115 | */ |
| f2e5a0c5 | 116 | function panels_menu() { |
| ee0e6fa9 EM |
117 | // Safety: go away if CTools is not at an appropriate version. |
| 118 | if (!module_invoke('ctools', 'api_version', PANELS_REQUIRED_CTOOLS_API)) { | |
| ab4648f3 EM |
119 | return array(); |
| 120 | } | |
| f2e5a0c5 EM |
121 | $items = array(); |
| 122 | ||
| 123 | // Provide some common options to reduce code repetition. | |
| 124 | // By using array addition and making sure these are the rightmost | |
| 125 | // value, they won't override anything already set. | |
| 126 | $base = array( | |
| 127 | 'access arguments' => array('access content'), | |
| 128 | 'type' => MENU_CALLBACK, | |
| 129 | 'file' => 'includes/display-edit.inc', | |
| 026b6377 | 130 | 'page arguments' => array(3), |
| f2e5a0c5 EM |
131 | ); |
| 132 | ||
| 026b6377 | 133 | $items['panels/ajax/add-pane/%panels_edit_cache'] = array( |
| f2e5a0c5 EM |
134 | 'page callback' => 'panels_ajax_add_pane_choose', |
| 135 | ) + $base; | |
| 026b6377 | 136 | $items['panels/ajax/add-pane-config/%panels_edit_cache'] = array( |
| f2e5a0c5 EM |
137 | 'page callback' => 'panels_ajax_add_pane_config', |
| 138 | ) + $base; | |
| 026b6377 | 139 | $items['panels/ajax/configure/%panels_edit_cache'] = array( |
| f2e5a0c5 EM |
140 | 'page callback' => 'panels_ajax_configure_pane', |
| 141 | ) + $base; | |
| 026b6377 | 142 | $items['panels/ajax/show/%panels_edit_cache'] = array( |
| f2e5a0c5 | 143 | 'page callback' => 'panels_ajax_toggle_shown', |
| 026b6377 | 144 | 'page arguments' => array('show', 3), |
| f2e5a0c5 | 145 | ) + $base; |
| 026b6377 | 146 | $items['panels/ajax/hide/%panels_edit_cache'] = array( |
| f2e5a0c5 | 147 | 'page callback' => 'panels_ajax_toggle_shown', |
| 026b6377 | 148 | 'page arguments' => array('hide', 3), |
| f2e5a0c5 | 149 | ) + $base; |
| 026b6377 | 150 | $items['panels/ajax/cache-method/%panels_edit_cache'] = array( |
| f2e5a0c5 EM |
151 | 'page callback' => 'panels_ajax_cache_method', |
| 152 | ) + $base; | |
| 026b6377 | 153 | $items['panels/ajax/cache-settings/%panels_edit_cache'] = array( |
| f2e5a0c5 EM |
154 | 'page callback' => 'panels_ajax_cache_settings', |
| 155 | ) + $base; | |
| 026b6377 | 156 | $items['panels/ajax/display-settings/%panels_edit_cache'] = array( |
| efcf7fcf EM |
157 | 'page callback' => 'panels_ajax_display_settings', |
| 158 | ) + $base; | |
| 026b6377 | 159 | $items['panels/ajax/style-type/%/%panels_edit_cache'] = array( |
| efcf7fcf | 160 | 'page callback' => 'panels_ajax_style_type', |
| 026b6377 | 161 | 'page arguments' => array(3, 4), |
| efcf7fcf | 162 | ) + $base; |
| 026b6377 | 163 | $items['panels/ajax/style-settings/%/%panels_edit_cache'] = array( |
| efcf7fcf | 164 | 'page callback' => 'panels_ajax_style_settings', |
| 026b6377 | 165 | 'page arguments' => array(3, 4), |
| efcf7fcf | 166 | ) + $base; |
| 026b6377 | 167 | $items['panels/ajax/pane-css/%panels_edit_cache'] = array( |
| efcf7fcf EM |
168 | 'page callback' => 'panels_ajax_configure_pane_css', |
| 169 | ) + $base; | |
| 026b6377 | 170 | $items['panels/ajax/access-settings/%panels_edit_cache'] = array( |
| efcf7fcf EM |
171 | 'page callback' => 'panels_ajax_configure_access_settings', |
| 172 | ) + $base; | |
| 026b6377 | 173 | $items['panels/ajax/access-test/%panels_edit_cache'] = array( |
| efcf7fcf EM |
174 | 'page callback' => 'panels_ajax_configure_access_test', |
| 175 | ) + $base; | |
| 026b6377 | 176 | $items['panels/ajax/access-add/%panels_edit_cache'] = array( |
| efcf7fcf EM |
177 | 'page callback' => 'panels_ajax_add_access_test', |
| 178 | ) + $base; | |
| 026b6377 | 179 | $items['panels/ajax/preview/%panels_edit_cache'] = array( |
| 66b7e481 | 180 | 'page callback' => 'panels_ajax_preview', |
| f2e5a0c5 | 181 | ) + $base; |
| f2e5a0c5 | 182 | |
| b2313b92 EM |
183 | $admin_base = array( |
| 184 | 'file' => 'includes/callbacks.inc', | |
| c5792555 | 185 | 'access arguments' => array('use panels dashboard'), |
| b2313b92 EM |
186 | |
| 187 | ); | |
| f2e5a0c5 | 188 | // Provide a nice location for a panels admin panel. |
| 287328f3 | 189 | $items['admin/build/panels'] = array( |
| 17a90678 | 190 | 'title' => 'Panels', |
| ade117f2 | 191 | 'page callback' => 'panels_admin_page', |
| 17a90678 | 192 | 'description' => 'Administer items related to the Panels module.', |
| b2313b92 | 193 | ) + $admin_base; |
| f2e5a0c5 | 194 | |
| 287328f3 EM |
195 | $items['admin/build/panels/dashboard'] = array( |
| 196 | 'title' => 'Dashboard', | |
| 287328f3 | 197 | 'page callback' => 'panels_admin_page', |
| 287328f3 EM |
198 | 'type' => MENU_DEFAULT_LOCAL_TASK, |
| 199 | 'weight' => -10, | |
| b2313b92 | 200 | ) + $admin_base; |
| 287328f3 EM |
201 | |
| 202 | $items['admin/build/panels/settings'] = array( | |
| 203 | 'title' => 'Settings', | |
| 287328f3 EM |
204 | 'page callback' => 'drupal_get_form', |
| 205 | 'page arguments' => array('panels_admin_settings_page'), | |
| 287328f3 | 206 | 'type' => MENU_LOCAL_TASK, |
| b2313b92 | 207 | ) + $admin_base; |
| 287328f3 EM |
208 | |
| 209 | $items['admin/build/panels/settings/general'] = array( | |
| 210 | 'title' => 'General', | |
| 287328f3 EM |
211 | 'page callback' => 'drupal_get_form', |
| 212 | 'page arguments' => array('panels_admin_settings_page'), | |
| 6a04891d | 213 | 'access arguments' => array('administer page manager'), |
| 287328f3 EM |
214 | 'type' => MENU_DEFAULT_LOCAL_TASK, |
| 215 | 'weight' => -10, | |
| b2313b92 EM |
216 | ) + $admin_base; |
| 217 | ||
| 6a04891d | 218 | if (module_exists('page_manager')) { |
| b2313b92 EM |
219 | $items['admin/build/panels/settings/panel-page'] = array( |
| 220 | 'title' => 'Panel pages', | |
| 221 | 'page callback' => 'panels_admin_panel_context_page', | |
| 222 | 'type' => MENU_LOCAL_TASK, | |
| 223 | 'weight' => -10, | |
| 224 | ) + $admin_base; | |
| 225 | } | |
| ec7ad513 | 226 | |
| a606b3ba | 227 | panels_load_include('plugins'); |
| efcf7fcf EM |
228 | $layouts = panels_get_layouts(); |
| 229 | foreach ($layouts as $name => $data) { | |
| 230 | if (!empty($data['hook menu'])) { | |
| 231 | if (is_array($data['hook menu'])) { | |
| 232 | $items += $data['hook menu']; | |
| 233 | } | |
| 234 | else if (function_exists($data['hook menu'])) { | |
| 235 | $data['hook menu']($items, $data); | |
| 236 | } | |
| 237 | } | |
| 238 | } | |
| ab4648f3 | 239 | |
| f2e5a0c5 | 240 | return $items; |
| 9f3609c9 EM |
241 | } |
| 242 | ||
| 243 | /** | |
| 026b6377 EM |
244 | * Menu loader function to load a cache item for Panels AJAX. |
| 245 | * | |
| 246 | * This load all of the includes needed to perform AJAX, and loads the | |
| 247 | * cache object and makes sure it is valid. | |
| 248 | */ | |
| 249 | function panels_edit_cache_load($cache_key) { | |
| 250 | panels_load_include('display-edit'); | |
| 251 | panels_load_include('plugins'); | |
| 252 | ctools_include('ajax'); | |
| 253 | ctools_include('modal'); | |
| 254 | ctools_include('context'); | |
| 255 | ||
| 256 | return panels_edit_cache_get($cache_key); | |
| 257 | } | |
| 258 | ||
| 259 | /** | |
| f2e5a0c5 | 260 | * Implementation of hook_init() |
| 9f3609c9 | 261 | */ |
| f2e5a0c5 | 262 | function panels_init() { |
| ee0e6fa9 EM |
263 | // Safety: go away if CTools is not at an appropriate version. |
| 264 | if (!module_invoke('ctools', 'api_version', PANELS_REQUIRED_CTOOLS_API)) { | |
| 265 | return; | |
| 266 | } | |
| 267 | ||
| f2e5a0c5 EM |
268 | drupal_add_css(panels_get_path('css/panels.css')); |
| 269 | drupal_add_js(panels_get_path('js/panels.js')); | |
| 9f3609c9 EM |
270 | } |
| 271 | ||
| 272 | /** | |
| f2e5a0c5 | 273 | * Load a panels include file. |
| 9f3609c9 | 274 | */ |
| f2e5a0c5 | 275 | function panels_load_include($include, $path = 'includes/') { |
| 0f4c2cf6 SB |
276 | static $loaded = array(); |
| 277 | if (empty($loaded["$path$include.inc"])) { | |
| 278 | require_once './' . panels_get_path("$path$include.inc"); | |
| 279 | $loaded["$path$include.inc"] = TRUE; | |
| 280 | } | |
| 9f3609c9 EM |
281 | } |
| 282 | ||
| 283 | /** | |
| 284 | * panels path helper function | |
| 285 | */ | |
| f2e5a0c5 EM |
286 | function panels_get_path($file, $base_path = FALSE, $module = 'panels') { |
| 287 | $output = $base_path ? base_path() : ''; | |
| 9f3609c9 EM |
288 | return $output . drupal_get_path('module', $module) . '/' . $file; |
| 289 | } | |
| 290 | ||
| f2e5a0c5 EM |
291 | /** |
| 292 | * Implementation of hook_perm | |
| 293 | */ | |
| 294 | function panels_perm() { | |
| 295 | return array( | |
| 296 | 'view all panes', | |
| 297 | 'view pane admin links', | |
| 298 | 'administer pane visibility', | |
| 299 | 'administer pane access', | |
| 300 | 'administer advanced pane settings', | |
| 3c7f35d6 | 301 | 'use panels caching features', |
| c5792555 | 302 | 'use panels dashboard', |
| f2e5a0c5 EM |
303 | ); |
| 304 | } | |
| 9f3609c9 EM |
305 | |
| 306 | /** | |
| f2e5a0c5 | 307 | * Get an object from cache. |
| 9f3609c9 | 308 | */ |
| f2e5a0c5 | 309 | function panels_cache_get($obj, $did, $skip_cache = FALSE) { |
| 5cf19555 | 310 | ctools_include('object-cache'); |
| d84ff3ec EM |
311 | // we often store contexts in cache, so let's just make sure we can load |
| 312 | // them. | |
| 313 | ctools_include('context'); | |
| 6a04891d | 314 | return ctools_object_cache_get($obj, 'panels_display:' . $did, $skip_cache); |
| 9f3609c9 EM |
315 | } |
| 316 | ||
| 317 | /** | |
| f2e5a0c5 | 318 | * Save the edited object into the cache. |
| 9f3609c9 | 319 | */ |
| f2e5a0c5 | 320 | function panels_cache_set($obj, $did, $cache) { |
| 5cf19555 | 321 | ctools_include('object-cache'); |
| 6a04891d | 322 | return ctools_object_cache_set($obj, 'panels_display:' . $did, $cache); |
| 9f3609c9 EM |
323 | } |
| 324 | ||
| f2e5a0c5 EM |
325 | /** |
| 326 | * Clear a object from the cache; used if the editing is aborted. | |
| 327 | */ | |
| 328 | function panels_cache_clear($obj, $did) { | |
| 5cf19555 | 329 | ctools_include('object-cache'); |
| 6a04891d | 330 | return ctools_object_cache_clear($obj, 'panels_display:' . $did); |
| f2e5a0c5 | 331 | } |
| 9f3609c9 | 332 | |
| 9f3609c9 | 333 | // --------------------------------------------------------------------------- |
| f2e5a0c5 | 334 | // panels display editing |
| 9f3609c9 EM |
335 | |
| 336 | /** | |
| f2e5a0c5 EM |
337 | * @defgroup mainapi Functions comprising the main panels API |
| 338 | * @{ | |
| 9f3609c9 | 339 | */ |
| 9f3609c9 | 340 | |
| f2e5a0c5 EM |
341 | /** |
| 342 | * Main API entry point to edit a panel display. | |
| 343 | * | |
| 344 | * Sample implementations utiltizing the the complex $destination behavior can be found | |
| 345 | * in panels_page_edit_content() and, in a separate contrib module, OG Blueprints | |
| 346 | * (http://drupal.org/project/og_blueprints), og_blueprints_blueprint_edit(). | |
| 347 | * | |
| 348 | * @ingroup mainapi | |
| 349 | * | |
| 350 | * @param object $display instanceof panels_display \n | |
| 351 | * A fully loaded panels $display object, as returned from panels_load_display(). | |
| 352 | * Merely passing a did is NOT sufficient. \n | |
| 353 | * Note that 'fully loaded' means the $display must already be loaded with any contexts | |
| 354 | * the caller wishes to have set for the display. | |
| 355 | * @param mixed $destination \n | |
| 356 | * The redirect destination that the user should be taken to on form submission or | |
| 357 | * cancellation. With panels_edit, $destination has complex effects on the return | |
| 358 | * values of panels_edit() once the form has been submitted. See the explanation of | |
| 359 | * the return value below to understand the different types of values returned by panels_edit() | |
| 360 | * at different stages of FAPI. Under most circumstances, simply passing in | |
| 361 | * drupal_get_destination() is all that's necessary. | |
| 362 | * @param array $content_types \n | |
| 363 | * An associative array of allowed content types, typically as returned from | |
| 364 | * panels_common_get_allowed_types(). Note that context partially governs available content types, | |
| 365 | * so you will want to create any relevant contexts using panels_create_context() or | |
| 366 | * panels_create_context_empty() to make sure all the appropriate content types are available. | |
| 367 | * | |
| 368 | * @return | |
| 369 | * Because the functions called by panels_edit() invoke the form API, this function | |
| 370 | * returns different values depending on the stage of form submission we're at. In Drupal 5, | |
| 371 | * the phase of form submission is indicated by the contents of $_POST['op']. Here's what you'll | |
| 372 | * get at different stages: | |
| 373 | * -# If !$_POST['op']: then we're on on the initial passthrough and the form is being | |
| 374 | * rendered, so it's the $form itself that's being returned. Because negative margins, | |
| 375 | * a common CSS technique, bork the display editor's ajax drag-and-drop, it's important | |
| 376 | * that the $output be printed, not returned. Use this syntax in the caller function: \n | |
| 377 | * print theme('page', panels_edit($display, $destination, $content_types), FALSE); \n | |
| 378 | * -# If $_POST['op'] == t('Cancel'): form submission has been cancelled. If empty($destination) == FALSE, | |
| 379 | * then there is no return value and the panels API takes care of redirecting to $destination. | |
| 380 | * If empty($destination) == TRUE, then there's still no return value, but the caller function | |
| 381 | * has to take care of form redirection. | |
| 382 | * -# If $_POST['op'] == ('Save'): the form has been submitted successfully and has run through | |
| 383 | * panels_edit_display_submit(). $output depends on the value of $destination: | |
| 384 | * - If empty($destination) == TRUE: $output contains the modified $display | |
| 385 | * object, and no redirection will occur. This option is useful if the caller | |
| 386 | * needs to perform additional operations on or with the modified $display before | |
| 387 | * the page request is complete. Using hook_form_alter() to add an additional submit | |
| 388 | * handler is typically the preferred method for something like this, but there | |
| 389 | * are certain use cases where that is infeasible and $destination = NULL should | |
| 390 | * be used instead. If this method is employed, the caller will need to handle form | |
| 391 | * redirection. Note that having $_REQUEST['destination'] set, whether via | |
| 392 | * drupal_get_destination() or some other method, will NOT interfere with this | |
| 393 | * functionality; consequently, you can use drupal_get_destination() to safely store | |
| 394 | * your desired redirect in the caller function, then simply use drupal_goto() once | |
| 395 | * panels_edit() has done its business. | |
| 396 | * - If empty($destination) == FALSE: the form will redirect to the URL string | |
| 397 | * given in $destination and NO value will be returned. | |
| 9f3609c9 | 398 | */ |
| efcf7fcf | 399 | function panels_edit($display, $destination = NULL, $content_types = NULL, $title = FALSE) { |
| f2e5a0c5 | 400 | panels_load_include('display-edit'); |
| 95f6686a | 401 | ctools_include('ajax'); |
| f2e5a0c5 | 402 | panels_load_include('plugins'); |
| efcf7fcf | 403 | return _panels_edit($display, $destination, $content_types, $title); |
| f2e5a0c5 | 404 | } |
| 9f3609c9 | 405 | |
| f2e5a0c5 EM |
406 | /** |
| 407 | * API entry point for selecting a layout for a given display. | |
| 408 | * | |
| 409 | * Layout selection is nothing more than a list of radio items encompassing the available | |
| 410 | * layouts for this display, as defined by .inc files in the panels/layouts subdirectory. | |
| 411 | * The only real complexity occurs when a user attempts to change the layout of a display | |
| 412 | * that has some content in it. | |
| 413 | * | |
| 414 | * @param object $display instanceof panels_display \n | |
| 415 | * A fully loaded panels $display object, as returned from panels_load_display(). | |
| 416 | * Merely passing a did is NOT sufficient. | |
| 417 | * @param string $finish | |
| 418 | * A string that will be used for the text of the form submission button. If no value is provided, | |
| 419 | * then the form submission button will default to t('Save'). | |
| 420 | * @param mixed $destination | |
| 421 | * Basic usage is a string containing the URL that the form should redirect to upon submission. | |
| 422 | * For a discussion of advanced usages, see panels_edit(). | |
| 423 | * @param mixed $allowed_layouts | |
| 424 | * Allowed layouts has three different behaviors that depend on which of three value types | |
| 425 | * are passed in by the caller: | |
| 426 | * #- if $allowed_layouts instanceof panels_allowed_layouts (includes subclasses): the most | |
| 427 | * complex use of the API. The caller is passing in a loaded panels_allowed_layouts object | |
| 428 | * that the client module previously created and stored somewhere using a custom storage | |
| 429 | * mechanism. | |
| 430 | * #- if is_string($allowed_layouts): the string will be used in a call to variable_get() which | |
| 431 | * will call the $allowed_layouts . '_allowed_layouts' var. If the data was stored properly | |
| 432 | * in the system var, the $allowed_layouts object will be unserialized and recreated. | |
| 433 | * @see panels_common_set_allowed_layouts() | |
| 434 | * #- if is_null($allowed_layouts): the default behavior, which also provides backwards | |
| 435 | * compatibility for implementations of the Panels2 API written before beta4. In this case, | |
| 436 | * a dummy panels_allowed_layouts object is created which does not restrict any layouts. | |
| 437 | * Subsequent behavior is indistinguishable from pre-beta4 behavior. | |
| 438 | * | |
| 439 | * @return | |
| 440 | * Can return nothing, or a modified $display object, or a redirection string; return values for the | |
| 441 | * panels_edit* family of functions are quite complex. See panels_edit() for detailed discussion. | |
| 442 | * @see panels_edit() | |
| 443 | */ | |
| 444 | function panels_edit_layout($display, $finish, $destination = NULL, $allowed_layouts = NULL) { | |
| 445 | panels_load_include('display-layout'); | |
| 446 | panels_load_include('plugins'); | |
| 447 | return _panels_edit_layout($display, $finish, $destination, $allowed_layouts); | |
| 9f3609c9 EM |
448 | } |
| 449 | ||
| f2e5a0c5 EM |
450 | /** |
| 451 | * API entry point for configuring the layout settings for a given display. | |
| 452 | * | |
| 453 | * For all layouts except Flexible, the layout settings form allows the user to select styles, | |
| 454 | * as defined by .inc files in the panels/styles subdirectory, for the panels in their display. | |
| 455 | * For the Flexible layout, the layout settings form allows the user to provide dimensions | |
| 456 | * for their flexible layout in addition to applying styles to panels. | |
| 457 | * | |
| 458 | * @param object $display instanceof panels_display \n | |
| 459 | * A fully loaded panels $display object, as returned from panels_load_display(). | |
| 460 | * Merely passing a did is NOT sufficient. | |
| 461 | * @param string $finish | |
| 462 | * A string that will be used for the text of (one of) the form submission button(s). Note that | |
| 463 | * panels will NOT wrap $finish in t() for you, so your caller should make sure to do so. \n | |
| 464 | * The submit behavior of the form is primarily governed by the value of $destination (see | |
| 465 | * below), but is secondarily governed by $finish as follows: | |
| 466 | * -# If $finish != t('Save'), then two #submit buttons will be present: one with the button | |
| 467 | * text t('Save'), and the other with the button text $finish. . | |
| 468 | * - Clicking the 'Save' button will save any changes on the form to the $display object and | |
| 469 | * keep the user on the same editing page. | |
| 470 | * - Clicking the $finish button will also save the $display object, but the user will be | |
| 471 | * redirected to the URL specified in $destination. | |
| 472 | * -# If $finish == t('Save'), then there is only one button, still called t('Save'), but it | |
| 473 | * mimics the behavior of the $finish button above by redirecting the user away from the form. | |
| 474 | * @param mixed $destination | |
| 475 | * Basic usage is a string containing the URL that the form should redirect to upon submission. | |
| 476 | * For a discussion of advanced usages that rely on NULL values for $destination, see the | |
| 477 | * panels_edit() documentation. | |
| 478 | * @param mixed $title | |
| 479 | * The $title variable has three modes of operation: | |
| 480 | * -# If $title == FALSE (the default), then no widget will appear on the panels_edit_layout_settings form | |
| 481 | * allowing the user to select a title, and other means for setting page titles will take precedent. If | |
| 482 | * no other means are used to provide a title, then the title will be hidden when rendering the $display. | |
| 483 | * -# If $title == TRUE, then two widgets will appear on the panels_edit_layout_settings form allowing the | |
| 484 | * user to input a title specific to this $display, as well as a checkbox enabling the user to disable | |
| 485 | * page titles entirely for this $display object. | |
| 486 | * -# If $title == (string), then the behavior is very similar to mode 2, but the widget description | |
| 487 | * on the title textfield will indicate that the $title string will be used as the default page title | |
| 488 | * if none is provided on this form. When utilizing this option, note that the panels API can only | |
| 489 | * provide the data for these values; you must implement the appropriate conditionals to make it true. | |
| 490 | * | |
| 491 | * @return | |
| 492 | * Can return nothing, or a modified $display object, or a redirection string; return values for the | |
| 493 | * panels_edit* family of functions are quite complex. See panels_edit() for detailed discussion. | |
| 494 | * @see panels_edit() | |
| 9f3609c9 | 495 | */ |
| f2e5a0c5 EM |
496 | function panels_edit_layout_settings($display, $finish, $destination = NULL, $title = FALSE) { |
| 497 | panels_load_include('display-layout-settings'); | |
| 95f6686a | 498 | ctools_include('ajax'); |
| f2e5a0c5 EM |
499 | panels_load_include('plugins'); |
| 500 | return _panels_edit_layout_settings($display, $finish, $destination, $title); | |
| 9f3609c9 EM |
501 | } |
| 502 | ||
| f2e5a0c5 EM |
503 | |
| 504 | // --------------------------------------------------------------------------- | |
| 505 | // panels database functions | |
| 506 | ||
| 9f3609c9 | 507 | /** |
| f2e5a0c5 EM |
508 | * Forms the basis of a panel display |
| 509 | * | |
| 9f3609c9 | 510 | */ |
| f2e5a0c5 EM |
511 | class panels_display { |
| 512 | var $args = array(); | |
| 513 | var $content = array(); | |
| 514 | var $panels = array(); | |
| 515 | var $incoming_content = NULL; | |
| 516 | var $css_id = NULL; | |
| 517 | var $context = array(); | |
| dce7d3e4 | 518 | var $did = 'new'; |
| f2e5a0c5 EM |
519 | |
| 520 | function add_pane($pane, $location = FALSE) { | |
| 521 | $pane->pid = $this->next_new_pid(); | |
| 522 | if (!$location || !isset($this->panels[$location])) { | |
| 523 | foreach ($this->panels as $panel_name => $panel) { | |
| 524 | if (array_key_exists($pane->pid, $panel)) { | |
| 525 | $this->panels[$panel_name][] = $pane->pid; | |
| 526 | } | |
| 9f3609c9 | 527 | } |
| 9f3609c9 | 528 | } |
| f2e5a0c5 EM |
529 | else { |
| 530 | $this->panels[$location][] = $pane->pid; | |
| 531 | } | |
| 9f3609c9 EM |
532 | } |
| 533 | ||
| f2e5a0c5 EM |
534 | function duplicate_pane($pid, $location = FALSE) { |
| 535 | $pane = $this->clone_pane($pid); | |
| 536 | $this->add_pane($pane, $location); | |
| 9f3609c9 EM |
537 | } |
| 538 | ||
| f2e5a0c5 EM |
539 | function clone_pane($pid) { |
| 540 | $pane = drupal_clone($this->content[$pid]); | |
| 541 | foreach (array_keys($this->content) as $pidcheck) { | |
| 542 | // necessary? | |
| 543 | unset($pane->position); | |
| 544 | } | |
| 545 | return $pane; | |
| 546 | } | |
| 9f3609c9 | 547 | |
| f2e5a0c5 EM |
548 | function next_new_pid() { |
| 549 | // necessary if/until we use this method and ONLY this method for adding temporary pids. | |
| 550 | // then we can do it with a nice static var. | |
| 551 | $id = array(0); | |
| 552 | foreach (array_keys($this->content) as $pid) { | |
| 553 | if (!is_numeric($pid)) { | |
| 554 | $id[] = substr($pid, 4); | |
| 555 | } | |
| 556 | } | |
| ae06d315 | 557 | $next_id = max($id); |
| f2e5a0c5 | 558 | return ++$next_id; |
| 9f3609c9 | 559 | } |
| 9f3609c9 EM |
560 | } |
| 561 | ||
| 562 | /** | |
| f2e5a0c5 | 563 | * }@ End of 'defgroup mainapi', although other functions are specifically added later |
| 9f3609c9 | 564 | */ |
| f2e5a0c5 | 565 | |
| 9f3609c9 | 566 | /** |
| f2e5a0c5 EM |
567 | * Clean up a display object and add some required information, if missing. |
| 568 | * | |
| 569 | * Currently a display object needs 'args', 'incoming content', 'context' | |
| 570 | * and a 'css_id'. | |
| 571 | * | |
| 572 | * @param &$display | |
| 573 | * The display object to be sanitized. | |
| 574 | * @return | |
| 575 | * The sanitized display object. | |
| 9f3609c9 | 576 | */ |
| f2e5a0c5 | 577 | function panels_sanitize_display(&$display) { |
| 3aa2f787 | 578 | return; |
| f2e5a0c5 EM |
579 | if (!isset($display->args)) { |
| 580 | $display->args = array(); | |
| 581 | } | |
| 9f3609c9 | 582 | |
| f2e5a0c5 EM |
583 | if (!isset($display->incoming_content)) { |
| 584 | $display->incoming_content = NULL; | |
| 585 | } | |
| 9f3609c9 | 586 | |
| f2e5a0c5 EM |
587 | if (!isset($display->context)) { |
| 588 | $display->context = array(); | |
| 589 | } | |
| 9f3609c9 | 590 | |
| f2e5a0c5 EM |
591 | if (!isset($display->css_id)) { |
| 592 | $display->css_id = NULL; | |
| 9f3609c9 | 593 | } |
| f2e5a0c5 | 594 | } |
| 9f3609c9 | 595 | |
| f2e5a0c5 EM |
596 | /** |
| 597 | * Creates a new display, setting the ID to our magic new id. | |
| 598 | */ | |
| 599 | function panels_new_display() { | |
| 9380e8a5 EM |
600 | ctools_include('export'); |
| 601 | $display = ctools_export_new_object('panels_display', FALSE); | |
| f2e5a0c5 EM |
602 | $display->did = 'new'; |
| 603 | return $display; | |
| 604 | } | |
| 9f3609c9 | 605 | |
| 5cf19555 EM |
606 | /** |
| 607 | * Create a new pane. | |
| 608 | * | |
| 609 | * @todo -- use schema API for some of this? | |
| 610 | */ | |
| f2e5a0c5 | 611 | function panels_new_pane($type, $subtype) { |
| 9380e8a5 EM |
612 | ctools_include('export'); |
| 613 | $pane = ctools_export_new_object('panels_pane', FALSE); | |
| f2e5a0c5 EM |
614 | $pane->pid = 'new'; |
| 615 | $pane->type = $type; | |
| 616 | $pane->subtype = $subtype; | |
| f2e5a0c5 EM |
617 | return $pane; |
| 618 | } | |
| 9f3609c9 | 619 | |
| f2e5a0c5 EM |
620 | /** |
| 621 | * Load and fill the requested $display object(s). | |
| 622 | * | |
| 623 | * Helper function primarily for for panels_load_display(). | |
| 624 | * | |
| 625 | * @param array $dids | |
| 626 | * An indexed array of dids to be loaded from the database. | |
| 627 | * | |
| 628 | * @return $displays | |
| 629 | * An array of displays, keyed by their display dids. | |
| 5cf19555 EM |
630 | * |
| 631 | * @todo schema API can drasticly simplify this code. | |
| f2e5a0c5 EM |
632 | */ |
| 633 | function panels_load_displays($dids) { | |
| 634 | $displays = array(); | |
| 635 | if (empty($dids) || !is_array($dids)) { | |
| 636 | return $displays; | |
| 637 | } | |
| 9f3609c9 | 638 | |
| 5cf19555 | 639 | $result = db_query("SELECT * FROM {panels_display} WHERE did IN (" . db_placeholders($dids) . ")", $dids); |
| 9f3609c9 | 640 | |
| 9380e8a5 EM |
641 | ctools_include('export'); |
| 642 | while ($obj = db_fetch_object($result)) { | |
| 643 | $displays[$obj->did] = ctools_export_unpack_object('panels_display', $obj); | |
| f2e5a0c5 EM |
644 | } |
| 645 | ||
| 9380e8a5 EM |
646 | // @TODO |
| 647 | // | |
| 648 | // This code clearly never worked ($content, $layout and $settings are all unset) | |
| 649 | // where was this supposed to even have been? | |
| 650 | ||
| 651 | // foreach (module_implements('panels_layout_content_alter') as $module) { | |
| 652 | // $function = $module . '_panels_layout_content_alter'; | |
| 653 | // $function($content, $layout, $settings); | |
| 654 | // } | |
| 9f3609c9 | 655 | |
| 5cf19555 | 656 | $result = db_query("SELECT * FROM {panels_pane} WHERE did IN (" . db_placeholders($dids) . ") ORDER BY did, panel, position", $dids); |
| 9f3609c9 | 657 | |
| 9380e8a5 EM |
658 | while ($obj = db_fetch_object($result)) { |
| 659 | $pane = ctools_export_unpack_object('panels_pane', $obj); | |
| f2e5a0c5 EM |
660 | |
| 661 | $displays[$pane->did]->panels[$pane->panel][] = $pane->pid; | |
| 662 | $displays[$pane->did]->content[$pane->pid] = $pane; | |
| 663 | } | |
| 9380e8a5 | 664 | |
| f2e5a0c5 | 665 | return $displays; |
| 9f3609c9 EM |
666 | } |
| 667 | ||
| 668 | /** | |
| f2e5a0c5 EM |
669 | * Load a single display. |
| 670 | * | |
| 671 | * @ingroup mainapi | |
| 672 | * | |
| 673 | * @param int $did | |
| 674 | * The display id (did) of the display to be loaded. | |
| 675 | * | |
| 676 | * @return object $display instanceof panels_display \n | |
| 677 | * Returns a partially-loaded panels_display object. $display objects returned from | |
| 678 | * from this function have only the following data: | |
| 679 | * - $display->did (the display id) | |
| 680 | * - $display->name (the 'name' of the display, where applicable - it often isn't) | |
| 681 | * - $display->layout (a string with the system name of the display's layout) | |
| 682 | * - $display->panel_settings (custom layout style settings contained in an associative array; NULL if none) | |
| 683 | * - $display->layout_settings (panel size and configuration settings for Flexible layouts; NULL if none) | |
| 684 | * - $display->css_id (the special css_id that has been assigned to this display, if any; NULL if none) | |
| 685 | * - $display->content (an array of pane objects, keyed by pane id (pid)) | |
| 686 | * - $display->panels (an associative array of panel regions, each an indexed array of pids in the order they appear in that region) | |
| 687 | * - $display->cache (any relevant data from panels_simple_cache) | |
| 688 | * - $display->args | |
| 689 | * - $display->incoming_content | |
| 690 | * | |
| 691 | * While all of these members are defined, $display->context is NEVER defined in the returned $display; | |
| b6a6c965 | 692 | * it must be set using one of the ctools_context_create() functions. |
| 9f3609c9 | 693 | */ |
| f2e5a0c5 EM |
694 | function panels_load_display($did) { |
| 695 | $displays = panels_load_displays(array($did)); | |
| 696 | if (!empty($displays)) { | |
| 697 | return array_shift($displays); | |
| 698 | } | |
| 699 | } | |
| 9f3609c9 | 700 | |
| f2e5a0c5 EM |
701 | /** |
| 702 | * Save a display object. | |
| 703 | * | |
| 704 | * @ingroup mainapi | |
| 705 | * | |
| 706 | * Note a new $display only receives a real did once it is run through this function. | |
| 707 | * Until then, it uses a string placeholder, 'new', in place of a real did. The same | |
| 708 | * applies to all new panes (whether on a new $display or not); in addition, | |
| 709 | * panes have sequential numbers appended, of the form 'new-1', 'new-2', etc. | |
| 710 | * | |
| 711 | * @param object $display instanceof panels_display \n | |
| 712 | * The display object to be saved. Passed by reference so the caller need not use | |
| 713 | * the return value for any reason except convenience. | |
| 714 | * | |
| 715 | * @return object $display instanceof panels_display \n | |
| 716 | */ | |
| 717 | function panels_save_display(&$display) { | |
| 9380e8a5 EM |
718 | $update = (isset($display->did) && is_numeric($display->did)) ? array('did') : array(); |
| 719 | drupal_write_record('panels_display', $display, $update); | |
| 720 | ||
| 721 | $pids = array(); | |
| 722 | if ($update) { | |
| f2e5a0c5 EM |
723 | // Get a list of all panes currently in the database for this display so we can know if there |
| 724 | // are panes that need to be deleted. (i.e, aren't currently in our list of panes). | |
| 725 | $result = db_query("SELECT pid FROM {panels_pane} WHERE did = %d", $display->did); | |
| 726 | while ($pane = db_fetch_object($result)) { | |
| 727 | $pids[$pane->pid] = $pane->pid; | |
| 9f3609c9 | 728 | } |
| f2e5a0c5 | 729 | } |
| 9f3609c9 | 730 | |
| f2e5a0c5 EM |
731 | // update all the panes |
| 732 | panels_load_include('plugins'); | |
| 66f397be | 733 | ctools_include('content'); |
| 9f3609c9 | 734 | |
| 9380e8a5 | 735 | foreach ($display->panels as $id => $panes) { |
| f2e5a0c5 EM |
736 | $position = 0; |
| 737 | $new_panes = array(); | |
| 738 | foreach ((array) $panes as $pid) { | |
| 746ca3a2 EM |
739 | if (!isset($display->content[$pid])) { |
| 740 | continue; | |
| 741 | } | |
| f2e5a0c5 | 742 | $pane = $display->content[$pid]; |
| d49e01de | 743 | $type = ctools_get_content_type($pane->type); |
| f2e5a0c5 | 744 | |
| 9380e8a5 EM |
745 | $pane->position = $position++; |
| 746 | $pane->did = $display->did; | |
| f2e5a0c5 | 747 | |
| 9380e8a5 EM |
748 | $old_pid = $pane->pid; |
| 749 | drupal_write_record('panels_pane', $pane, is_numeric($pid) ? array('pid') : array()); | |
| f2e5a0c5 | 750 | |
| 9380e8a5 EM |
751 | if ($pane->pid != $old_pid) { |
| 752 | // and put it back so our pids and positions can be used | |
| 753 | unset($display->content[$id]); | |
| 754 | $display->content[$pane->pid] = $pane; | |
| f2e5a0c5 | 755 | } |
| 9380e8a5 EM |
756 | |
| 757 | // re-add this to the list of content for this panel. | |
| f2e5a0c5 | 758 | $new_panes[] = $pane->pid; |
| 9380e8a5 EM |
759 | |
| 760 | // Remove this from the list of panes scheduled for deletion. | |
| f2e5a0c5 EM |
761 | if (isset($pids[$pane->pid])) { |
| 762 | unset($pids[$pane->pid]); | |
| 9f3609c9 EM |
763 | } |
| 764 | } | |
| 9f3609c9 | 765 | |
| f2e5a0c5 EM |
766 | $display->panels[$id] = $new_panes; |
| 767 | } | |
| f6c1a273 | 768 | if (!empty($pids)) { |
| f2e5a0c5 | 769 | db_query("DELETE FROM {panels_pane} WHERE pid IN (" . db_placeholders($pids) . ")", $pids); |
| 9f3609c9 | 770 | } |
| 9f3609c9 | 771 | |
| f2e5a0c5 EM |
772 | // Clear any cached content for this display. |
| 773 | panels_clear_cached_content($display); | |
| 9f3609c9 | 774 | |
| f2e5a0c5 EM |
775 | // to be nice, even tho we have a reference. |
| 776 | return $display; | |
| 9f3609c9 EM |
777 | } |
| 778 | ||
| 779 | /** | |
| f2e5a0c5 | 780 | * Delete a display. |
| 9f3609c9 | 781 | */ |
| f2e5a0c5 EM |
782 | function panels_delete_display($display) { |
| 783 | if (is_object($display)) { | |
| 784 | $did = $display->did; | |
| 785 | } | |
| 786 | else { | |
| 787 | $did = $display; | |
| 788 | } | |
| 789 | db_query("DELETE FROM {panels_display} WHERE did = %d", $did); | |
| 790 | db_query("DELETE FROM {panels_pane} WHERE did = %d", $did); | |
| 9f3609c9 EM |
791 | } |
| 792 | ||
| 793 | /** | |
| f2e5a0c5 EM |
794 | * Exports the provided display into portable code. |
| 795 | * | |
| 796 | * This function is primarily intended as a mechanism for cloning displays. | |
| 797 | * It generates an exact replica (in code) of the provided $display, with | |
| 798 | * the exception that it replaces all ids (dids and pids) with 'new-*' values. | |
| 799 | * Only once panels_save_display() is called on the code version of $display will | |
| 800 | * the exported display written to the database and permanently saved. | |
| 801 | * | |
| 802 | * @see panels_page_export() or _panels_page_fetch_display() for sample implementations. | |
| 803 | * | |
| 804 | * @ingroup mainapi | |
| 805 | * | |
| 806 | * @param object $display instanceof panels_display \n | |
| 807 | * This export function does no loading of additional data about the provided | |
| 808 | * display. Consequently, the caller should make sure that all the desired data | |
| 809 | * has been loaded into the $display before calling this function. | |
| 810 | * @param string $prefix | |
| 811 | * A string prefix that is prepended to each line of exported code. This is primarily | |
| 812 | * used for prepending a double space when exporting so that the code indents and lines up nicely. | |
| 813 | * | |
| 814 | * @return string $output | |
| 815 | * The passed-in $display expressed as code, ready to be imported. Import by running | |
| 816 | * eval($output) in the caller function; doing so will create a new $display variable | |
| 817 | * with all the exported values. Note that if you have already defined a $display variable in | |
| 818 | * the same scope as where you eval(), your existing $display variable WILL be overwritten. | |
| 9f3609c9 | 819 | */ |
| f2e5a0c5 | 820 | function panels_export_display($display, $prefix = '') { |
| 9380e8a5 EM |
821 | ctools_include('export'); |
| 822 | $output = ctools_export_object('panels_display', $display, $prefix); | |
| 9f3609c9 | 823 | |
| f2e5a0c5 EM |
824 | $output .= $prefix . '$display->content = array()' . ";\n"; |
| 825 | $output .= $prefix . '$display->panels = array()' . ";\n"; | |
| 826 | $panels = array(); | |
| 827 | ||
| 828 | if (!empty($display->content)) { | |
| 829 | $pid_counter = 0; | |
| 830 | $region_counters = array(); | |
| 831 | foreach ($display->content as $pane) { | |
| 832 | $pane->pid = 'new-' . ++$pid_counter; | |
| 9380e8a5 | 833 | $output .= ctools_export_object('panels_pane', $pane, $prefix . ' '); |
| f2e5a0c5 EM |
834 | $output .= "$prefix " . '$display->content[\'' . $pane->pid . '\'] = $pane' . ";\n"; |
| 835 | if (!isset($region_counters[$pane->panel])) { | |
| 836 | $region_counters[$pane->panel] = 0; | |
| 9f3609c9 | 837 | } |
| f2e5a0c5 | 838 | $output .= "$prefix " . '$display->panels[\'' . $pane->panel . '\'][' . $region_counters[$pane->panel]++ .'] = \'' . $pane->pid . "';\n"; |
| 9f3609c9 EM |
839 | } |
| 840 | } | |
| f2e5a0c5 | 841 | return $output; |
| 9f3609c9 EM |
842 | } |
| 843 | ||
| f2e5a0c5 EM |
844 | /** |
| 845 | * Render a display by loading the content into an appropriate | |
| 846 | * array and then passing through to panels_render_layout. | |
| 847 | * | |
| 848 | * if $incoming_content is NULL, default content will be applied. Use | |
| 849 | * an empty string to indicate no content. | |
| 850 | * @render | |
| 851 | * @ingroup hook_invocations | |
| 852 | */ | |
| 853 | function panels_render_display(&$display) { | |
| 854 | panels_load_include('display-render'); | |
| 855 | panels_load_include('plugins'); | |
| d75b98c7 EM |
856 | ctools_include('context'); |
| 857 | ||
| 858 | if (!empty($display->context)) { | |
| 859 | if ($form_context = ctools_context_get_form($display->context)) { | |
| 860 | $form_context->form['#theme'] = 'panels_render_display_form'; | |
| 861 | $form_context->form['#display'] = &$display; | |
| 862 | $form_context->form['#form_context_id'] = $form_context->id; | |
| 863 | return drupal_render_form($form_context->form_id, $form_context->form); | |
| 864 | } | |
| 865 | } | |
| f2e5a0c5 | 866 | return _panels_render_display($display); |
| 9f3609c9 EM |
867 | } |
| 868 | ||
| 869 | /** | |
| d75b98c7 EM |
870 | * Theme function to render our panel as a form. |
| 871 | * | |
| 872 | * When rendering a display as a form, the entire display needs to be | |
| 873 | * inside the <form> tag so that the form can be spread across the | |
| 874 | * panes. This sets up the form system to be the main caller and we | |
| 875 | * then operate as a theme function of the form. | |
| 876 | */ | |
| 877 | function theme_panels_render_display_form($form) { | |
| 878 | $form['#children'] = _panels_render_display($form['#display']); | |
| 879 | drupal_render($form); | |
| 880 | return theme('form', $form); | |
| 881 | } | |
| 882 | ||
| d75b98c7 | 883 | /** |
| 9f3609c9 | 884 | * For external use: Given a layout ID and a $content array, return the |
| f2e5a0c5 EM |
885 | * panel display. The content array is filled in based upon the content |
| 886 | * available in the layout. If it's a two column with a content | |
| 887 | * array defined like array('left' => t('Left side'), 'right' => | |
| 888 | * t('Right side')), then the $content array should be array('left' => | |
| 889 | * $output_left, 'right' => $output_right) | |
| 890 | * @render | |
| 9f3609c9 EM |
891 | */ |
| 892 | function panels_print_layout($id, $content) { | |
| f2e5a0c5 EM |
893 | panels_load_include('plugins'); |
| 894 | return _panels_print_layout($id, $content); | |
| 9f3609c9 EM |
895 | } |
| 896 | ||
| f2e5a0c5 EM |
897 | // @layout |
| 898 | function panels_print_layout_icon($id, $layout, $title = NULL) { | |
| 899 | drupal_add_css(panels_get_path('css/panels_admin.css')); | |
| fc8f8fa8 | 900 | $file = $layout['path'] . '/' . $layout['icon']; |
| f2e5a0c5 | 901 | return theme('panels_layout_icon', $id, theme('image', $file), $title); |
| 9f3609c9 EM |
902 | } |
| 903 | ||
| f2e5a0c5 EM |
904 | /** |
| 905 | * Theme the layout icon image | |
| 906 | * @layout | |
| 907 | * @todo move to theme.inc | |
| 908 | */ | |
| 909 | function theme_panels_layout_icon($id, $image, $title = NULL) { | |
| 14996ee1 | 910 | $output = '<div class="layout-icon">'; |
| f2e5a0c5 EM |
911 | $output .= $image; |
| 912 | if ($title) { | |
| 913 | $output .= '<div class="caption">' . $title . '</div>'; | |
| 9f3609c9 | 914 | } |
| f2e5a0c5 EM |
915 | $output .= '</div>'; |
| 916 | return $output; | |
| 9f3609c9 EM |
917 | } |
| 918 | ||
| 919 | /** | |
| f2e5a0c5 EM |
920 | * Theme the layout link image |
| 921 | * @layout | |
| 9f3609c9 | 922 | */ |
| f2e5a0c5 | 923 | function theme_panels_layout_link($title, $id, $image, $link) { |
| 14996ee1 | 924 | $output = '<div class="layout-link">'; |
| f2e5a0c5 EM |
925 | $output .= $image; |
| 926 | $output .= '<div>' . $title . '</div>'; | |
| 927 | $output .= '</div>'; | |
| 928 | return $output; | |
| 9f3609c9 | 929 | } |
| aa3e4818 EM |
930 | |
| 931 | /** | |
| 932 | * Print the layout link. Sends out to a theme function. | |
| 933 | * @layout | |
| 934 | */ | |
| a2329e43 EM |
935 | function panels_print_layout_link($id, $layout, $link, $options = array()) { |
| 936 | if (isset($options['query']['q'])) { | |
| 937 | unset($options['query']['q']); | |
| 938 | } | |
| 939 | ||
| aa3e4818 EM |
940 | drupal_add_css(panels_get_path('css/panels_admin.css')); |
| 941 | $file = $layout['path'] . '/' . $layout['icon']; | |
| a2329e43 EM |
942 | $image = l(theme('image', $file), $link, array('html' => true) + $options); |
| 943 | $title = l($layout['title'], $link, $options); | |
| aa3e4818 EM |
944 | return theme('panels_layout_link', $title, $id, $image, $link); |
| 945 | } | |
| 946 | ||
| b76f0bd4 SB |
947 | /** |
| 948 | * Implementation of hook_ctools_plugin_directory() to let the system know | |
| 949 | * we implement task and task_handler plugins. | |
| 950 | */ | |
| b6a6c965 | 951 | function panels_ctools_plugin_directory($module, $plugin) { |
| 2db8bc72 EM |
952 | // Safety: go away if CTools is not at an appropriate version. |
| 953 | if (!module_invoke('ctools', 'api_version', PANELS_REQUIRED_CTOOLS_API)) { | |
| 954 | return; | |
| 955 | } | |
| 6a04891d | 956 | if ($module == 'page_manager' || $module == 'panels') { |
| b76f0bd4 SB |
957 | return 'plugins/' . $plugin; |
| 958 | } | |
| 959 | } | |
| 050cfb22 EM |
960 | |
| 961 | /** | |
| 962 | * Inform CTools that the layout plugin can be loaded from themes. | |
| 963 | */ | |
| 964 | function panels_ctools_plugin_layouts() { | |
| 965 | return array( | |
| 966 | 'load themes' => TRUE, | |
| 967 | ); | |
| 968 | } | |
| efcf7fcf EM |
969 | |
| 970 | /** | |
| 971 | * Inform CTools that the style plugin can be loaded from themes. | |
| 972 | */ | |
| 973 | function panels_ctools_plugin_styles() { | |
| 974 | return array( | |
| 975 | 'load themes' => TRUE, | |
| 976 | ); | |
| 977 | } | |
| 978 | ||
| 2505a50c EM |
979 | /** |
| 980 | * Get the display that is currently being rendered as a page. | |
| ee0e6fa9 | 981 | * |
| 2505a50c EM |
982 | * Unlike in previous versions of this, this only returns the display, |
| 983 | * not the page itself, because there are a number of different ways | |
| 984 | * to get to this point. It is hoped that the page data isn't needed | |
| 985 | * at this point. If it turns out there is, we will do something else to | |
| 986 | * get that functionality. | |
| 987 | */ | |
| 988 | function panels_get_current_page_display($change = NULL) { | |
| 989 | static $display = NULL; | |
| 990 | if ($change) { | |
| 991 | $display = $change; | |
| 992 | } | |
| 993 | ||
| 994 | return $display; | |
| 995 | } | |
| 026b6377 EM |
996 | |
| 997 | /** | |
| 998 | * Get display edit cache on behalf of panel context. | |
| 999 | * | |
| 1000 | * The key is the second half of the key in this form: | |
| 1001 | * panel_context:TASK_NAME:HANDLER_NAME; | |
| 1002 | */ | |
| 1003 | function panel_context_panels_cache_get($key) { | |
| 1004 | panels_load_include('common'); | |
| 51ddcbf4 | 1005 | ctools_include('context'); |
| 026b6377 EM |
1006 | ctools_include('context-task-handler'); |
| 1007 | // this loads the panel context inc even if we don't use the plugin. | |
| 1008 | $plugin = page_manager_get_task_handler('panel_context'); | |
| 1009 | ||
| 1010 | list($task_name, $handler_name) = explode(':', $key, 2); | |
| 1011 | $page = page_manager_get_page_cache($task_name); | |
| 1012 | if (isset($page->display_cache[$handler_name])) { | |
| 1013 | return $page->display_cache[$handler_name]; | |
| 1014 | } | |
| 1015 | ||
| 51ddcbf4 EM |
1016 | if ($handler_name) { |
| 1017 | $handler = &$page->handlers[$handler_name]; | |
| 1018 | } | |
| 1019 | else { | |
| 1020 | $handler = &$page->new_handler; | |
| 1021 | } | |
| 026b6377 | 1022 | $cache = new stdClass(); |
| 40ab7380 EM |
1023 | |
| 1024 | $cache->display = &panels_panel_context_get_display($handler); | |
| 026b6377 EM |
1025 | $cache->display->context = ctools_context_handler_get_all_contexts($page->task, $page->subtask, $handler); |
| 1026 | $cache->display->cache_key = 'panel_context:' . $key; | |
| 1027 | $cache->content_types = panels_common_get_allowed_types('panels_page', $cache->display->context); | |
| 1028 | $cache->display_title = TRUE; | |
| 1029 | ||
| 1030 | return $cache; | |
| 1031 | } | |
| 1032 | ||
| 1033 | /** | |
| 1034 | * Store a display edit in progress in the page cache. | |
| 1035 | */ | |
| 1036 | function panel_context_panels_cache_set($key, $cache) { | |
| 1037 | list($task_name, $handler_name) = explode(':', $key, 2); | |
| 1038 | $page = page_manager_get_page_cache($task_name); | |
| 1039 | $page->display_cache[$handler_name] = $cache; | |
| 51ddcbf4 EM |
1040 | if ($handler_name) { |
| 1041 | $page->handlers[$handler_name]->conf['display'] = $cache->display; | |
| 1042 | $page->handler_info[$handler_name]['changed'] |= PAGE_MANAGER_CHANGED_CACHED; | |
| 1043 | } | |
| 1044 | else { | |
| 1045 | $page->new_handler->conf['display'] = $cache->display; | |
| 1046 | } | |
| 026b6377 EM |
1047 | page_manager_set_page_cache($page); |
| 1048 | } |