4 define('PANELS_ARG_IS_BAD', 1);
5 define('PANELS_ARG_USE_FALLBACK', 1 << 1);
8 * Returns the API version of Panels. This didn't exist in 1.
10 * @return An array with the major and minor versions
12 function panels_api_version() {
16 function panels_theme() {
18 $theme['panels_layout_link'] = array(
19 'arguments' => array('title', 'id', 'image', 'link'),
21 $theme['panels_layout_icon'] = array(
22 'arguments' => array('id', 'image', 'title' => NULL
),
24 $theme['panels_imagebutton'] = array(
25 'arguments' => array('element'),
27 $theme['panels_edit_display_form'] = array(
28 'arguments' => array('form'),
29 'file' => 'includes/display-edit.inc',
31 $theme['panels_edit_layout_form_choose'] = array(
32 'arguments' => array('form'),
33 'file' => 'includes/display-edit.inc',
35 $theme['panels_pane'] = array(
36 'arguments' => array('content', 'pane', 'display'),
37 'file' => 'includes/display-render.inc',
39 $theme['panels_common_content_list'] = array(
40 'arguments' => array('display'),
41 'file' => 'includes/common.inc',
43 $theme['panels_common_context_list'] = array(
44 'arguments' => array('object'),
45 'file' => 'includes/common.inc',
47 $theme['panels_common_context_item_form'] = array(
48 'arguments' => array('form'),
49 'file' => 'includes/common.inc',
51 $theme['panels_common_context_item_row'] = array(
52 'arguments' => array('type', 'form', 'position', 'count', 'with_tr' => TRUE
),
53 'file' => 'includes/common.inc',
55 $theme['panels_dnd'] = array(
56 'arguments' => array('content'),
57 'file' => 'includes/display-edit.inc',
58 'function' => 'theme_panels_dnd',
60 $theme['panels_panel_dnd'] = array(
61 'arguments' => array('content', 'area', 'label', 'footer'),
62 'file' => 'includes/display-edit.inc',
63 'function' => 'theme_panels_panel_dnd',
65 $theme['panels_pane_dnd'] = array(
66 'arguments' => array('block', 'id', 'label', 'left_buttons' => NULL
, 'buttons' => NULL
),
67 'file' => 'includes/display-edit.inc',
69 $theme['panels_pane_collapsible'] = array(
70 'arguments' => array('block'),
71 'file' => 'includes/display-edit.inc',
74 // Register layout and style themes on behalf of all of these items.
75 panels_load_include('plugins');
77 // No need to worry about files; the plugin has to already be loaded for us
78 // to even know what the theme function is, so files will be auto included.
79 $layouts = panels_get_layouts();
80 foreach ($layouts as
$name => $data) {
81 if (!empty($data['theme'])) {
82 $theme[$data['theme']] = array(
83 'arguments' => array('css_id' => NULL
, 'content' => NULL
, 'settings' => NULL
),
84 'path' => $data['path'],
87 // if no theme function exists, assume template.
88 if (!function_exists("theme_$data[theme]")) {
89 $theme[$data['theme']]['template'] = str_replace('_', '-', $data['theme']);
94 $styles = panels_get_styles();
95 foreach ($styles as
$name => $data) {
96 if (!empty($data['render pane'])) {
97 $theme[$data['render pane']] = array(
98 'arguments' => array('content' => NULL
, 'pane' => NULL
, 'display' => NULL
),
101 if (!empty($data['render panel'])) {
102 $theme[$data['render panel']] = array(
103 'arguments' => array('display' => NULL
, 'panel_id' => NULL
, 'panes' => NULL
, 'settings' => NULL
),
113 * Implementation of hook_menu
115 function panels_menu() {
118 // Provide some common options to reduce code repetition.
119 // By using array addition and making sure these are the rightmost
120 // value, they won't override anything already set.
122 'access arguments' => array('access content'),
123 'type' => MENU_CALLBACK
,
124 'file' => 'includes/display-edit.inc',
127 $items['panels/ajax/add-pane'] = array(
128 'page callback' => 'panels_ajax_add_pane_choose',
130 $items['panels/ajax/add-pane-config'] = array(
131 'page callback' => 'panels_ajax_add_pane_config',
133 $items['panels/ajax/configure'] = array(
134 'page callback' => 'panels_ajax_configure_pane',
136 $items['panels/ajax/show'] = array(
137 'page callback' => 'panels_ajax_toggle_shown',
138 'page arguments' => array('show'),
140 $items['panels/ajax/hide'] = array(
141 'page callback' => 'panels_ajax_toggle_shown',
142 'page arguments' => array('hide'),
144 $items['panels/ajax/cache-method'] = array(
145 'page callback' => 'panels_ajax_cache_method',
147 $items['panels/ajax/cache-settings'] = array(
148 'page callback' => 'panels_ajax_cache_settings',
151 // For panel settings on the edit layout settings page
152 $items['panels/ajax/style-settings'] = array(
153 'page callback' => 'panels_ajax_style_settings',
154 'file' => 'includes/display-layout-settings.inc',
157 // Non-display editor callbacks
158 $items['panels/node/autocomplete'] = array(
159 'title' => 'Autocomplete node',
160 'page callback' => 'panels_node_autocomplete',
161 'file' => 'includes/callbacks.inc',
164 // For context add/configure calls in common-context.inc
165 $items['panels/ajax/context-add'] = array(
166 'page callback' => 'panels_ajax_context_item_add',
167 'file' => 'includes/common-context.inc',
169 $items['panels/ajax/context-configure'] = array(
170 'page callback' => 'panels_ajax_context_item_edit',
171 'file' => 'includes/common-context.inc',
173 $items['panels/ajax/context-delete'] = array(
174 'page callback' => 'panels_ajax_context_item_delete',
175 'file' => 'includes/common-context.inc',
178 // Provide a nice location for a panels admin panel.
179 $items['admin/panels'] = array(
181 'access arguments' => array('access administration pages'),
182 'page callback' => 'panels_admin_page',
183 'file' => 'includes/callbacks.inc',
184 'description' => 'Administer items related to the Panels module.',
191 * Implementation of hook_init()
193 function panels_init() {
194 drupal_add_css(panels_get_path('css/panels.css'));
195 drupal_add_js(panels_get_path('js/panels.js'));
199 * Load a panels include file.
201 function panels_load_include($include, $path = 'includes/') {
202 static
$loaded = array();
203 if (empty($loaded["$path$include.inc"])) {
204 require_once
'./' .
panels_get_path("$path$include.inc");
205 $loaded["$path$include.inc"] = TRUE
;
210 * panels path helper function
212 function panels_get_path($file, $base_path = FALSE
, $module = 'panels') {
213 $output = $base_path ?
base_path() : '';
214 return $output .
drupal_get_path('module', $module) .
'/' .
$file;
218 * Implementation of hook_perm
220 function panels_perm() {
223 'view pane admin links',
224 'administer pane visibility',
225 'administer pane access',
226 'administer advanced pane settings',
227 'use panels caching features'
232 * Get an object from cache.
234 function panels_cache_get($obj, $did, $skip_cache = FALSE
) {
235 static
$cache = array();
241 if (!array_key_exists($key, $cache)) {
242 $data = db_fetch_object(db_query("SELECT * FROM {panels_object_cache} WHERE sid = '%s' AND obj = '%s' AND did = %d", session_id(), $obj, $did));
244 $cache[$key] = unserialize($data->data
);
247 return isset($cache[$key]) ?
$cache[$key] : NULL
;
251 * Save the edited object into the cache.
253 function panels_cache_set($obj, $did, $cache) {
254 panels_cache_clear($obj, $did);
255 db_query("INSERT INTO {panels_object_cache} (sid, obj, did, data, timestamp) VALUES ('%s', '%s', %d, '%s', %d)", session_id(), $obj, $did, serialize($cache), time());
259 * Clear a object from the cache; used if the editing is aborted.
261 function panels_cache_clear($obj, $did) {
262 db_query("DELETE FROM {panels_object_cache} WHERE sid = '%s' AND obj = '%s' AND did = %d", session_id(), $obj, $did);
266 * Implementation of hook_cron. Clean up old caches.
268 function panels_cron() {
269 // delete anything 7 days old or more.
270 db_query("DELETE FROM {panels_object_cache} WHERE timestamp < %d", time() - (86400 * 7));
273 // ---------------------------------------------------------------------------
274 // panels display editing
277 * @defgroup mainapi Functions comprising the main panels API
282 * Main API entry point to edit a panel display.
284 * Sample implementations utiltizing the the complex $destination behavior can be found
285 * in panels_page_edit_content() and, in a separate contrib module, OG Blueprints
286 * (http://drupal.org/project/og_blueprints), og_blueprints_blueprint_edit().
290 * @param object $display instanceof panels_display \n
291 * A fully loaded panels $display object, as returned from panels_load_display().
292 * Merely passing a did is NOT sufficient. \n
293 * Note that 'fully loaded' means the $display must already be loaded with any contexts
294 * the caller wishes to have set for the display.
295 * @param mixed $destination \n
296 * The redirect destination that the user should be taken to on form submission or
297 * cancellation. With panels_edit, $destination has complex effects on the return
298 * values of panels_edit() once the form has been submitted. See the explanation of
299 * the return value below to understand the different types of values returned by panels_edit()
300 * at different stages of FAPI. Under most circumstances, simply passing in
301 * drupal_get_destination() is all that's necessary.
302 * @param array $content_types \n
303 * An associative array of allowed content types, typically as returned from
304 * panels_common_get_allowed_types(). Note that context partially governs available content types,
305 * so you will want to create any relevant contexts using panels_create_context() or
306 * panels_create_context_empty() to make sure all the appropriate content types are available.
309 * Because the functions called by panels_edit() invoke the form API, this function
310 * returns different values depending on the stage of form submission we're at. In Drupal 5,
311 * the phase of form submission is indicated by the contents of $_POST['op']. Here's what you'll
312 * get at different stages:
313 * -# If !$_POST['op']: then we're on on the initial passthrough and the form is being
314 * rendered, so it's the $form itself that's being returned. Because negative margins,
315 * a common CSS technique, bork the display editor's ajax drag-and-drop, it's important
316 * that the $output be printed, not returned. Use this syntax in the caller function: \n
317 * print theme('page', panels_edit($display, $destination, $content_types), FALSE); \n
318 * -# If $_POST['op'] == t('Cancel'): form submission has been cancelled. If empty($destination) == FALSE,
319 * then there is no return value and the panels API takes care of redirecting to $destination.
320 * If empty($destination) == TRUE, then there's still no return value, but the caller function
321 * has to take care of form redirection.
322 * -# If $_POST['op'] == ('Save'): the form has been submitted successfully and has run through
323 * panels_edit_display_submit(). $output depends on the value of $destination:
324 * - If empty($destination) == TRUE: $output contains the modified $display
325 * object, and no redirection will occur. This option is useful if the caller
326 * needs to perform additional operations on or with the modified $display before
327 * the page request is complete. Using hook_form_alter() to add an additional submit
328 * handler is typically the preferred method for something like this, but there
329 * are certain use cases where that is infeasible and $destination = NULL should
330 * be used instead. If this method is employed, the caller will need to handle form
331 * redirection. Note that having $_REQUEST['destination'] set, whether via
332 * drupal_get_destination() or some other method, will NOT interfere with this
333 * functionality; consequently, you can use drupal_get_destination() to safely store
334 * your desired redirect in the caller function, then simply use drupal_goto() once
335 * panels_edit() has done its business.
336 * - If empty($destination) == FALSE: the form will redirect to the URL string
337 * given in $destination and NO value will be returned.
339 function panels_edit($display, $destination = NULL
, $content_types = NULL
) {
340 panels_load_include('display-edit');
341 panels_load_include('ajax');
342 panels_load_include('plugins');
343 return _panels_edit($display, $destination, $content_types);
347 * API entry point for selecting a layout for a given display.
349 * Layout selection is nothing more than a list of radio items encompassing the available
350 * layouts for this display, as defined by .inc files in the panels/layouts subdirectory.
351 * The only real complexity occurs when a user attempts to change the layout of a display
352 * that has some content in it.
354 * @param object $display instanceof panels_display \n
355 * A fully loaded panels $display object, as returned from panels_load_display().
356 * Merely passing a did is NOT sufficient.
357 * @param string $finish
358 * A string that will be used for the text of the form submission button. If no value is provided,
359 * then the form submission button will default to t('Save').
360 * @param mixed $destination
361 * Basic usage is a string containing the URL that the form should redirect to upon submission.
362 * For a discussion of advanced usages, see panels_edit().
363 * @param mixed $allowed_layouts
364 * Allowed layouts has three different behaviors that depend on which of three value types
365 * are passed in by the caller:
366 * #- if $allowed_layouts instanceof panels_allowed_layouts (includes subclasses): the most
367 * complex use of the API. The caller is passing in a loaded panels_allowed_layouts object
368 * that the client module previously created and stored somewhere using a custom storage
370 * #- if is_string($allowed_layouts): the string will be used in a call to variable_get() which
371 * will call the $allowed_layouts . '_allowed_layouts' var. If the data was stored properly
372 * in the system var, the $allowed_layouts object will be unserialized and recreated.
373 * @see panels_common_set_allowed_layouts()
374 * #- if is_null($allowed_layouts): the default behavior, which also provides backwards
375 * compatibility for implementations of the Panels2 API written before beta4. In this case,
376 * a dummy panels_allowed_layouts object is created which does not restrict any layouts.
377 * Subsequent behavior is indistinguishable from pre-beta4 behavior.
380 * Can return nothing, or a modified $display object, or a redirection string; return values for the
381 * panels_edit* family of functions are quite complex. See panels_edit() for detailed discussion.
384 function panels_edit_layout($display, $finish, $destination = NULL
, $allowed_layouts = NULL
) {
385 panels_load_include('display-layout');
386 panels_load_include('plugins');
387 return _panels_edit_layout($display, $finish, $destination, $allowed_layouts);
391 * API entry point for configuring the layout settings for a given display.
393 * For all layouts except Flexible, the layout settings form allows the user to select styles,
394 * as defined by .inc files in the panels/styles subdirectory, for the panels in their display.
395 * For the Flexible layout, the layout settings form allows the user to provide dimensions
396 * for their flexible layout in addition to applying styles to panels.
398 * @param object $display instanceof panels_display \n
399 * A fully loaded panels $display object, as returned from panels_load_display().
400 * Merely passing a did is NOT sufficient.
401 * @param string $finish
402 * A string that will be used for the text of (one of) the form submission button(s). Note that
403 * panels will NOT wrap $finish in t() for you, so your caller should make sure to do so. \n
404 * The submit behavior of the form is primarily governed by the value of $destination (see
405 * below), but is secondarily governed by $finish as follows:
406 * -# If $finish != t('Save'), then two #submit buttons will be present: one with the button
407 * text t('Save'), and the other with the button text $finish. .
408 * - Clicking the 'Save' button will save any changes on the form to the $display object and
409 * keep the user on the same editing page.
410 * - Clicking the $finish button will also save the $display object, but the user will be
411 * redirected to the URL specified in $destination.
412 * -# If $finish == t('Save'), then there is only one button, still called t('Save'), but it
413 * mimics the behavior of the $finish button above by redirecting the user away from the form.
414 * @param mixed $destination
415 * Basic usage is a string containing the URL that the form should redirect to upon submission.
416 * For a discussion of advanced usages that rely on NULL values for $destination, see the
417 * panels_edit() documentation.
418 * @param mixed $title
419 * The $title variable has three modes of operation:
420 * -# If $title == FALSE (the default), then no widget will appear on the panels_edit_layout_settings form
421 * allowing the user to select a title, and other means for setting page titles will take precedent. If
422 * no other means are used to provide a title, then the title will be hidden when rendering the $display.
423 * -# If $title == TRUE, then two widgets will appear on the panels_edit_layout_settings form allowing the
424 * user to input a title specific to this $display, as well as a checkbox enabling the user to disable
425 * page titles entirely for this $display object.
426 * -# If $title == (string), then the behavior is very similar to mode 2, but the widget description
427 * on the title textfield will indicate that the $title string will be used as the default page title
428 * if none is provided on this form. When utilizing this option, note that the panels API can only
429 * provide the data for these values; you must implement the appropriate conditionals to make it true.
432 * Can return nothing, or a modified $display object, or a redirection string; return values for the
433 * panels_edit* family of functions are quite complex. See panels_edit() for detailed discussion.
436 function panels_edit_layout_settings($display, $finish, $destination = NULL
, $title = FALSE
) {
437 panels_load_include('display-layout-settings');
438 panels_load_include('ajax');
439 panels_load_include('plugins');
440 return _panels_edit_layout_settings($display, $finish, $destination, $title);
444 // ---------------------------------------------------------------------------
445 // panels database functions
448 * Forms the basis of a panel display
451 class panels_display
{
453 var
$content = array();
454 var
$panels = array();
455 var
$incoming_content = NULL
;
457 var
$context = array();
458 var
$layout_settings = array();
459 var
$panel_settings = array();
460 var
$cache = array();
464 function add_pane($pane, $location = FALSE
) {
465 $pane->pid
= $this->next_new_pid();
466 if (!$location || !isset($this->panels
[$location])) {
467 foreach ($this->panels as
$panel_name => $panel) {
468 if (array_key_exists($pane->pid
, $panel)) {
469 $this->panels
[$panel_name][] = $pane->pid
;
474 $this->panels
[$location][] = $pane->pid
;
478 function duplicate_pane($pid, $location = FALSE
) {
479 $pane = $this->clone_pane($pid);
480 $this->add_pane($pane, $location);
483 function clone_pane($pid) {
484 $pane = drupal_clone($this->content
[$pid]);
485 foreach (array_keys($this->content
) as
$pidcheck) {
487 unset($pane->position
);
492 function next_new_pid() {
493 // necessary if/until we use this method and ONLY this method for adding temporary pids.
494 // then we can do it with a nice static var.
496 foreach (array_keys($this->content
) as
$pid) {
497 if (!is_numeric($pid)) {
498 $id[] = substr($pid, 4);
507 * }@ End of 'defgroup mainapi', although other functions are specifically added later
510 function panels_export_pane_across_displays($source_display, &$target_display, $pid, $location = FALSE
) {
511 $pane = $source_display->clone_pane($pid);
512 $target_display->add_pane($pane, $location);
516 * Clean up a display object and add some required information, if missing.
518 * Currently a display object needs 'args', 'incoming content', 'context'
522 * The display object to be sanitized.
524 * The sanitized display object.
526 function panels_sanitize_display(&$display) {
527 if (!isset($display->args
)) {
528 $display->args
= array();
531 if (!isset($display->incoming_content
)) {
532 $display->incoming_content
= NULL
;
535 if (!isset($display->context
)) {
536 $display->context
= array();
539 if (!isset($display->css_id
)) {
540 $display->css_id
= NULL
;
545 * Creates a new display, setting the ID to our magic new id.
547 function panels_new_display() {
548 $display = new
panels_display();
549 $display->did
= 'new';
553 function panels_new_pane($type, $subtype) {
554 $pane = new
stdClass();
557 $pane->subtype
= $subtype;
558 $pane->configuration
= array();
559 $pane->access
= array();
561 $pane->visibility
= '';
566 * Load and fill the requested $display object(s).
568 * Helper function primarily for for panels_load_display().
571 * An indexed array of dids to be loaded from the database.
574 * An array of displays, keyed by their display dids.
576 function panels_load_displays($dids) {
578 if (empty($dids) || !is_array($dids)) {
582 $subs = implode(', ', array_fill(0, count($dids), '%d'));
584 $result = db_query("SELECT * FROM {panels_display} WHERE did IN ($subs)", $dids);
586 while ($obj = db_fetch_array($result)) {
587 $display = new
panels_display();
589 foreach ($obj as
$key => $value) {
590 $display->$key = $value;
591 // unserialize important bits
592 if (in_array($key, array('layout_settings', 'panel_settings', 'cache'))) {
593 $display->$key = empty($display->$key) ?
array() : unserialize($display->$key);
597 $display->panels
= $display->content
= array();
599 $displays[$display->did
] = $display;
602 foreach (module_implements('panels_layout_content_alter') as
$module) {
603 $function = $module .
'_panels_layout_content_alter';
604 $function($content, $layout, $settings);
607 $result = db_query("SELECT * FROM {panels_pane} WHERE did IN ($subs) ORDER BY did, panel, position", $dids);
609 while ($pane = db_fetch_object($result)) {
610 $pane->configuration
= unserialize($pane->configuration
);
611 $pane->cache
= empty($pane->cache
) ?
array() : unserialize($pane->cache
);
612 $pane->access
= ($pane->access ?
explode(', ', $pane->access
) : array());
613 // Old panels may not have shown property, so enable by default when loading.
614 $pane->shown
= isset($pane->shown
) ?
$pane->shown
: TRUE
;
616 $displays[$pane->did
]->panels
[$pane->panel
][] = $pane->pid
;
617 $displays[$pane->did
]->content
[$pane->pid
] = $pane;
623 * Load a single display.
628 * The display id (did) of the display to be loaded.
630 * @return object $display instanceof panels_display \n
631 * Returns a partially-loaded panels_display object. $display objects returned from
632 * from this function have only the following data:
633 * - $display->did (the display id)
634 * - $display->name (the 'name' of the display, where applicable - it often isn't)
635 * - $display->layout (a string with the system name of the display's layout)
636 * - $display->panel_settings (custom layout style settings contained in an associative array; NULL if none)
637 * - $display->layout_settings (panel size and configuration settings for Flexible layouts; NULL if none)
638 * - $display->css_id (the special css_id that has been assigned to this display, if any; NULL if none)
639 * - $display->content (an array of pane objects, keyed by pane id (pid))
640 * - $display->panels (an associative array of panel regions, each an indexed array of pids in the order they appear in that region)
641 * - $display->cache (any relevant data from panels_simple_cache)
643 * - $display->incoming_content
645 * While all of these members are defined, $display->context is NEVER defined in the returned $display;
646 * it must be set using one of the panels_context_create() functions.
648 function panels_load_display($did) {
649 $displays = panels_load_displays(array($did));
650 if (!empty($displays)) {
651 return array_shift($displays);
656 * Save a display object.
660 * Note a new $display only receives a real did once it is run through this function.
661 * Until then, it uses a string placeholder, 'new', in place of a real did. The same
662 * applies to all new panes (whether on a new $display or not); in addition,
663 * panes have sequential numbers appended, of the form 'new-1', 'new-2', etc.
665 * @param object $display instanceof panels_display \n
666 * The display object to be saved. Passed by reference so the caller need not use
667 * the return value for any reason except convenience.
669 * @return object $display instanceof panels_display \n
671 function panels_save_display(&$display) {
672 // @todo -- update all this to just use drupal_write_record or something like it.
673 if (!empty($display->did
) && $display->did
!= 'new') {
674 db_query("UPDATE {panels_display} SET layout = '%s', layout_settings = '%s', panel_settings = '%s', cache = '%s', title = '%s', hide_title = %d WHERE did = %d", $display->layout
, serialize($display->layout_settings
), serialize($display->panel_settings
), serialize($display->cache
), $display->title
, $display->hide_title
, $display->did
);
675 // Get a list of all panes currently in the database for this display so we can know if there
676 // are panes that need to be deleted. (i.e, aren't currently in our list of panes).
677 $result = db_query("SELECT pid FROM {panels_pane} WHERE did = %d", $display->did
);
678 while ($pane = db_fetch_object($result)) {
679 $pids[$pane->pid
] = $pane->pid
;
683 db_query("INSERT INTO {panels_display} (layout, layout_settings, panel_settings, cache, title, hide_title) VALUES ('%s', '%s', '%s', '%s', '%s', %d)", $display->layout
, serialize($display->layout_settings
), serialize($display->panel_settings
), serialize($display->cache
), $display->title
, $display->hide_title
);
684 $display->did
= db_last_insert_id('panels_display', 'did');
688 // update all the panes
689 panels_load_include('plugins');
691 foreach ((array) $display->panels as
$id => $panes) {
693 $new_panes = array();
694 foreach ((array) $panes as
$pid) {
695 $pane = $display->content
[$pid];
696 $pane->position
= $position++;
698 // make variables right.
699 $type = panels_get_content_type($pane->type
);
700 $access = isset($pane->access
) ?
implode(', ', $pane->access
) : '';
701 $visibility = !empty($type['visibility serialize']) ?
serialize($pane->visibility
) : $pane->visibility
;
702 $pane->shown
= isset($pane->shown
) ?
$pane->shown
: TRUE
;
704 if (empty($pane->cache
)) {
705 $pane->cache
= array();
708 $v = array($display->did
, $pane->panel
, $pane->type
, $pane->subtype
, serialize($pane->configuration
), serialize($pane->cache
), $pane->shown
, $access, $visibility, $pane->position
);
710 if (!is_numeric($pid)) {
711 unset($display->content
[$pid]);
712 // doin it this way for readability
713 $f = 'did, panel, type, subtype, configuration, cache, shown, access, visibility, position';
714 $q = "%d, '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', %d";
716 db_query("INSERT INTO {panels_pane} ($f) VALUES ($q)", $v);
717 $pane->pid
= db_last_insert_id('panels_pane', 'pid');
721 $f = "did = %d, panel = '%s', type = '%s', subtype = '%s', configuration = '%s', cache = '%s', shown = '%s', access = '%s', visibility = '%s', position = '%d'";
722 db_query("UPDATE {panels_pane} SET $f WHERE pid = %d", $v);
724 // and put it back so our pids and positions can be used
725 $display->content
[$pane->pid
] = $pane;
726 $new_panes[] = $pane->pid
;
727 if (isset($pids[$pane->pid
])) {
728 unset($pids[$pane->pid
]);
732 $display->panels
[$id] = $new_panes;
735 db_query("DELETE FROM {panels_pane} WHERE pid IN (" .
db_placeholders($pids) .
")", $pids);
738 // Clear any cached content for this display.
739 panels_clear_cached_content($display);
741 // to be nice, even tho we have a reference.
748 function panels_delete_display($display) {
749 if (is_object($display)) {
750 $did = $display->did
;
755 db_query("DELETE FROM {panels_display} WHERE did = %d", $did);
756 db_query("DELETE FROM {panels_pane} WHERE did = %d", $did);
760 * Exports the provided display into portable code.
762 * This function is primarily intended as a mechanism for cloning displays.
763 * It generates an exact replica (in code) of the provided $display, with
764 * the exception that it replaces all ids (dids and pids) with 'new-*' values.
765 * Only once panels_save_display() is called on the code version of $display will
766 * the exported display written to the database and permanently saved.
768 * @see panels_page_export() or _panels_page_fetch_display() for sample implementations.
772 * @param object $display instanceof panels_display \n
773 * This export function does no loading of additional data about the provided
774 * display. Consequently, the caller should make sure that all the desired data
775 * has been loaded into the $display before calling this function.
776 * @param string $prefix
777 * A string prefix that is prepended to each line of exported code. This is primarily
778 * used for prepending a double space when exporting so that the code indents and lines up nicely.
780 * @return string $output
781 * The passed-in $display expressed as code, ready to be imported. Import by running
782 * eval($output) in the caller function; doing so will create a new $display variable
783 * with all the exported values. Note that if you have already defined a $display variable in
784 * the same scope as where you eval(), your existing $display variable WILL be overwritten.
786 function panels_export_display($display, $prefix = '') {
788 $output .
= $prefix .
'$display = new panels_display()' .
";\n";
789 $output .
= $prefix .
'$display->did = \'new\'' .
";\n";
790 // $fields = array('name', 'layout', 'layout_settings', 'panel_settings');
791 // TODO 'name' field was removed several months ago, so temporarily removing
792 // it from here whil investigations into exactly why it was removed continue
793 $fields = array('layout', 'layout_settings', 'panel_settings');
794 foreach ($fields as
$field) {
795 $output .
= $prefix .
'$display->' .
$field .
' = ' .
panels_var_export($display->$field, $prefix) .
";\n";
798 $output .
= $prefix .
'$display->content = array()' .
";\n";
799 $output .
= $prefix .
'$display->panels = array()' .
";\n";
802 if (!empty($display->content
)) {
804 $region_counters = array();
805 foreach ($display->content as
$pane) {
806 $pane->pid
= 'new-' .
++$pid_counter;
807 $output .
= panels_export_pane($pane, $prefix .
' ');
808 $output .
= "$prefix " .
'$display->content[\'' .
$pane->pid .
'\'] = $pane' .
";\n";
809 if (!isset($region_counters[$pane->panel
])) {
810 $region_counters[$pane->panel
] = 0;
812 $output .
= "$prefix " .
'$display->panels[\'' .
$pane->panel .
'\'][' .
$region_counters[$pane->panel
]++ .
'] = \'' .
$pane->pid .
"';\n";
818 function panels_export_pane($pane, $prefix = '') {
820 $output = $prefix .
'$pane = new stdClass()' .
";\n";
821 $fields = array('pid', 'panel', 'type', 'subtype', 'access', 'configuration');
822 foreach ($fields as
$field) {
823 $output .
= "$prefix " .
'$pane->' .
$field .
' = ' .
panels_var_export($pane->$field, "$prefix ") .
";\n";
828 function panels_var_export($object, $prefix = '') {
829 if (is_array($object) && empty($object)) {
833 // Remove extra space to match Drupal coding standards.
834 $output = str_replace('array (', 'array(', var_export($object, TRUE
));
838 $output = str_replace("\n", "\n$prefix", $output);
844 * Render a display by loading the content into an appropriate
845 * array and then passing through to panels_render_layout.
847 * if $incoming_content is NULL, default content will be applied. Use
848 * an empty string to indicate no content.
850 * @ingroup hook_invocations
852 function panels_render_display(&$display) {
853 panels_load_include('display-render');
854 panels_load_include('plugins');
855 return _panels_render_display($display);
859 * For external use: Given a layout ID and a $content array, return the
860 * panel display. The content array is filled in based upon the content
861 * available in the layout. If it's a two column with a content
862 * array defined like array('left' => t('Left side'), 'right' =>
863 * t('Right side')), then the $content array should be array('left' =>
864 * $output_left, 'right' => $output_right)
867 function panels_print_layout($id, $content) {
868 panels_load_include('plugins');
869 return _panels_print_layout($id, $content);
873 function panels_print_layout_icon($id, $layout, $title = NULL
) {
874 drupal_add_css(panels_get_path('css/panels_admin.css'));
875 $file = $layout['path'] .
'/' .
$layout['icon'];
876 return theme('panels_layout_icon', $id, theme('image', $file), $title);
880 * Theme the layout icon image
882 * @todo move to theme.inc
884 function theme_panels_layout_icon($id, $image, $title = NULL
) {
885 $output = '<div class="layout-icon">';
888 $output .
= '<div class="caption">' .
$title .
'</div>';
895 * Theme the layout link image
898 function theme_panels_layout_link($title, $id, $image, $link) {
899 $output = '<div class="layout-link">';
901 $output .
= '<div>' .
$title .
'</div>';
907 * Print the layout link. Sends out to a theme function.
910 function panels_print_layout_link($id, $layout, $link) {
911 drupal_add_css(panels_get_path('css/panels_admin.css'));
912 $file = $layout['path'] .
'/' .
$layout['icon'];
913 $image = l(theme('image', $file), $link, array('html' => true
));
914 $title = l($layout['title'], $link);
915 return theme('panels_layout_link', $title, $id, $image, $link);