'panels/node/autocomplete', 'title' => t('Autocomplete node'), 'callback' => 'panels_node_autocomplete', 'access' => user_access('access content'), 'type' => MENU_CALLBACK ); $items[] = array( 'path' => 'panels/ajax', 'title' => t('ajax'), 'callback' => 'panels_ajax', 'access' => user_access('access content'), 'type' => MENU_CALLBACK ); $items[] = array( 'path' => 'panels/ajax/add-content', 'title' => t('ajax'), 'callback' => 'panels_ajax_add_content', 'access' => user_access('access content'), 'type' => MENU_CALLBACK ); $items[] = array( 'path' => 'panels/ajax/add-config', 'title' => t('ajax'), 'callback' => 'panels_ajax_add_config', 'access' => user_access('access content'), 'type' => MENU_CALLBACK ); $items[] = array( 'path' => 'panels/ajax/configure', 'title' => t('ajax'), 'callback' => 'panels_ajax_configure', 'access' => user_access('access content'), 'type' => MENU_CALLBACK ); } return $items; } /** * panels path helper function */ function panels_get_path($file, $base_path = false, $module = 'panels') { if ($base_path) { $output = base_path(); } return $output . drupal_get_path('module', $module) . '/' . $file; } /** * Implementation of hook_perm */ function panels_perm() { return array('view all panes', 'administer pane visibility', 'administer advanced pane settings'); } /** * Determine visibility of a panel pane */ function panels_pane_access($pane, $account = NULL) { if (!$account) { global $user; $account = $user; } // Administrator privileges if (user_access('view all pane', $account)) { return TRUE; } // All views with an empty access setting are available to all roles. if (!$pane->access || !is_array($pane->access)) { return TRUE; } // Otherwise, check roles static $roles = array(); if (!isset($roles[$account->uid])) { $roles[$account->uid] = array_keys($account->roles); $roles[$account->uid][] = $account->uid ? DRUPAL_AUTHENTICATED_RID : DRUPAL_ANONYMOUS_RID; } return array_intersect($pane->access, $roles[$account->uid]); } // --------------------------------------------------------------------------- // panels custom image button /** * Custom form element to do our nice images. */ function panels_elements() { $type['panels_imagebutton'] = array('#input' => TRUE, '#button_type' => 'submit',); return $type; } /** * Theme our image button. */ function theme_panels_imagebutton($element) { return '\n"; } function panels_imagebutton_value() { // null function guarantees default_value doesn't get moved to #value. } /** * Add a single button to a form. */ function panels_add_button($image, $name, $text, $class, $id = NULL) { return array( '#type' => 'panels_imagebutton', '#image' => panels_get_path('images/' . $image, true), '#title' => $text, '#default_value' => $name, '#class' => $class, '#id' => $id, ); } // --------------------------------------------------------------------------- // cache handling stuff for display editing /** * Get a display from the cache; this is used if the display is currently * being edited, which can be a seriously multi-step process. */ function panels_cache_get($did) { static $cache = array(); if (!array_key_exists($did, $cache)) { $data = cache_get(session_id() . ':' . $did, 'cache'); $cache[$did] = unserialize($data->data); } return $cache[$did]; } /** * Save the edited display into the cache. */ function panels_cache_set($did, $cache) { cache_set(session_id() . ':' . $did, 'cache', serialize($cache), time() + 86400); } /** * Clear a display from the cache; used if the editing is aborted. */ function panels_cache_clear($did) { cache_clear_all(session_id() . ':' . $did, 'cache'); } /** * Global storage function, used mostly so that _submit hooks can pass data * back to their originator more easily. */ function panels_set($var, $value = NULL) { static $vars = array(); if ($value !== NULL) { $vars[$var] = $value; } return $vars[$var]; } /** * Retrieve from global storage */ function panels_get($var) { return panels_set($var); } // --------------------------------------------------------------------------- // panels display editing /** * Main API entry point to edit a panel display. * * TODO: Doc this. Important. */ function panels_edit($display, $destination, $content_types = NULL) { $did = $display->did; if (!$did) { $display->did = $did = 'new'; } // Load the display being edited from cache, if possible. if (!empty($_POST) && is_object($cache = panels_cache_get($did))) { $display = $cache->display; } else { panels_cache_clear($did); $cache = new stdClass(); $cache->display = $display; $cache->highest = 0; $cache->content_types = $content_types; panels_cache_set($did, $cache); } // drupal_set_message('
' . check_plain(var_export($display, true)) . '
'); $output = drupal_get_form('panels_edit_display', $display, $destination); $hidden = theme('panels_hidden'); return $output . $hidden; } /** * Form definition for the panels display editor */ function panels_edit_display($display, $destination) { $form['did'] = array( '#type' => 'hidden', '#value' => $display->did, '#id' => 'panel-did', ); $form['op'] = array( '#type' => 'hidden', '#id' => 'panel-op', ); $form['panels_display'] = array( '#type' => 'value', '#value' => $display ); $form['destination'] = array( '#type' => 'value', '#value' => $destination ); $form['explanation'] = array( '#value' => '

' . t('Grab the title bar of any pane to drag it to another panel. Click the add pane button in any panel to add more content. Click the configure button on any pane to re-configure that pane.') . '

', ); $form['button']['#tree'] = TRUE; foreach ($display->content as $pid => $panel) { $form['button'][$pid]['#tree'] = TRUE; $form['button'][$pid]['configure'] = panels_add_button('configure.gif', t('Configure'), t('Configure this pane'), 'pane-configure'); $form['button'][$pid]['delete'] = panels_add_button('close.gif', t('Delete'), t('Remove this pane'), 'pane-delete'); } $layout = panels_get_layout($display->layout); $layout_panels = panels_get_panels($layout, $display); foreach ($layout_panels as $id => $name) { $form['panels'][$id]['add'] = panels_add_button('add.gif', t('Add content'), t('Add content to this panel'), 'pane-add', "pane-add-$id"); } $form['panel'] = array('#tree' => TRUE); $form['panel']['pane'] = array('#tree' => TRUE); foreach ($layout_panels as $panel_id => $title) { $form['panel']['pane'][$panel_id] = array( '#type' => 'hidden', '#default_value' => implode(',', (array) $display->panels[$panel_id]), ); } $form['submit'] = array( '#type' => 'submit', '#value' => t('Save'), '#id' => 'panels-dnd-save', ); $form['cancel'] = array( '#type' => 'submit', '#value' => t('Cancel'), ); $form['hide'] = array( '#prefix' => '', '#suffix' => '', ); $form['hide']['hide-all'] = array( '#type' => 'submit', '#value' => t('Hide all'), '#id' => 'panels-hide-all', ); $form['hide']['show-all'] = array( '#type' => 'submit', '#value' => t('Show all'), '#id' => 'panels-show-all', ); if ($submit) { // The caller wants their own submit. $form['#submit'] = array($submit => array()); } return $form; } function theme_panels_edit_display($form) { _panels_js_files(); $display = $form['panels_display']['#value']; $layout = panels_get_layout($display->layout); $layout_panels = panels_get_panels($layout, $display); $save_buttons = drupal_render($form['submit']) . drupal_render($form['cancel']); foreach ($layout_panels as $panel_id => $title) { foreach ((array) $display->panels[$panel_id] as $pid) { $pane = $display->content[$pid]; $left_buttons = NULL; $buttons = drupal_render($form['button'][$pid]['configure']); $buttons .= drupal_render($form['button'][$pid]['delete']); $content[$pane->panel] .= panels_show_pane($pane, $left_buttons, $buttons); } $content[$panel_id] = theme('panels_panel_dnd', $content[$panel_id], $panel_id, $title, drupal_render($form['panels'][$panel_id]['add'])); } $output .= drupal_render($form); $output .= theme('panels_dnd', panels_render_layout($layout, $content, '', unserialize($display->layout_settings))); $output .= $save_buttons; return $output; } function panels_edit_display_submit($form_id, $form_values) { $display = $form_values['panels_display']; if ($form_values['op'] == t('Save')) { // drupal_set_message('
' . var_export($display, true) . '
'); // drupal_set_message('
' . var_export($form_values, true) . '
'); $old_content = $display->content; $display->content = array(); foreach ($form_values['panel']['pane'] as $panel_id => $panes) { $display->panels[$panel_id] = array(); if ($panes) { $pids = explode(',', $panes); foreach ($pids as $pid) { if ($old_content[$pid]) { $display->panels[$panel_id][] = $pid; $old_content[$pid]->panel = $panel_id; $display->content[$pid] = $old_content[$pid]; } } } } // drupal_set_message('
' . var_export($display, true) . '
'); drupal_set_message(t('Panel content has been updated.')); panels_save_display($display); } panels_cache_clear($display->did); return $form_values['destination']; } /** * Shortcut to the panels layout editor * * TODO: Doc this. Important. */ function panels_edit_layout($display, $finish, $destination) { return drupal_get_form('panels_choose_layout', $display, $finish, $destination); } /** * Form to change the layout of a display. */ function panels_choose_layout($display, $finish, $destination) { $layouts = panels_get_layouts(); foreach ($layouts as $id => $layout) { $options[$id] = panels_print_layout_icon($id, $layout, check_plain($layout['title'])); } drupal_add_js(panels_get_path('js/layout.js')); $form['layout'] = array( '#type' => 'radios', '#title' => t('Choose layout'), '#options' => $options, '#default_value' => $display->layout, ); $form['clearer'] = array( '#value' => '
', ); $form['variables'] = array( '#type' => 'value', '#value' => array($display, $finish, $destination), ); if ($_POST['op'] && $_POST['op'] != t('Back') && $display->content) { $form['#post'] = $_POST; $form = form_builder('panels_choose_layout', $form); unset($form['#post']); $form['layout']['#type'] = 'hidden'; panels_change_layout($form, $display, $form['layout']['#value']); } if (($_POST['op'] && $_POST['op'] != t('Back')) || !$display->content) { $form['submit'] = array( '#type' => 'submit', '#value' => $finish, ); } else { $form['submit'] = array( '#type' => 'submit', '#value' => t('Next'), ); } $form['#token'] = FALSE; // no token please return $form; } function panels_choose_layout_submit($form_id, $form_values) { list($display, $finish, $destination) = $form_values['variables']; $new_layout_id = $form_values['layout']; if ($form_values['op'] == $finish) { if (!empty($form_values['old'])) { foreach ($form_values['old'] as $id => $new_id) { $content[$new_id] = array_merge((array) $content[$new_id], $display->panels[$id]); foreach($content[$new_id] as $pid) { $display->content[$pid]->panel = $new_id; } } $display->panels = $content; } $display->layout = $new_layout_id; // save it back to our session. panels_save_display($display); return $destination; } return FALSE; } function panels_change_layout(&$form, $display, $new_layout_id) { $new_layout = panels_get_layout($new_layout_id); $new_layout_panels = panels_get_panels($new_layout, $display); $options = $new_layout_panels; $keys = array_keys($options); $default = $options[0]; $old_layout = panels_get_layout($display->layout); $form['container'] = array( '#prefix' => '
', '#suffix' => '
', ); $form['container']['old_layout'] = array( '#value' => panels_print_layout_icon($display->layout, $old_layout, check_plain($old_layout['title'])), ); $form['container']['right_arrow'] = array( '#value' => theme('image', drupal_get_path('module', 'panels') . '/images/go-right.png'), ); $form['container']['new_layout'] = array( '#value' => panels_print_layout_icon($new_layout_id, $new_layout, check_plain($new_layout['title'])), ); $form['container-clearer'] = array( '#value' => '
', ); $form['old'] = array( '#tree' => true, '#prefix' => '
', '#suffix' => '
', ); $old_layout_panels = panels_get_panels($old_layout, $display); foreach ($display->panels as $id => $content) { $form['old'][$id] = array( '#type' => 'select', '#title' => t('Move content in @layout to', array('@layout' => $old_layout_panels[$id])), '#options' => $options, '#default_value' => array_key_exists($id, $options) ? $id : $default, ); } $form['back'] = array( '#type' => 'submit', '#value' => t('Back'), ); return $form; } /** * Shortcut to the panels layout settings editor * * TODO: Doc this. Important. */ function panels_edit_layout_settings($display, $finish, $destination) { return drupal_get_form('panels_edit_layout_settings_form', $display, $finish, $destination); } /** * Form to change the layout of a display. */ function panels_edit_layout_settings_form($display, $finish, $destination) { $layout = panels_get_layout($display->layout); if (!empty($layout['settings form']) && function_exists($layout['settings form'])) { $form['layout_settings'] = $layout['settings form']($display, $layout, unserialize($display->layout_settings)); } $form['layout_settings']['#tree'] = TRUE; $form['variables'] = array( '#type' => 'value', '#value' => array($display, $finish, $destination), ); $form['layout'] = array( '#type' => 'value', '#value' => $layout, ); $form['submit'] = array( '#type' => 'submit', '#value' => $finish, ); return $form; } function panels_edit_layout_settings_form_validate($form_id, $form_values, $form) { list($display, $finish, $destination) = $form_values['variables']; $layout = $form_values['layout']; if (!empty($layout['settings validate']) && function_exists($layout['settings validate'])) { $layout['settings validate']($form_values['layout_settings'], $form['layout_settings'], $display, $layout, unserialize($display->layout_settings)); } } function panels_edit_layout_settings_form_submit($form_id, $form_values) { list($display, $finish, $destination) = $form_values['variables']; $layout = $form_values['layout']; if (!empty($layout['settings submit']) && function_exists($layout['settings submit'])) { $layout['settings submit']($form_values['layout_settings'], $display, $layout, unserialize($display->layout_settings)); } if ($form_values['op'] == $finish) { $display->layout_settings = serialize($form_values['layout_settings']); panels_save_display($display); drupal_set_message("Your layout settings have been saved."); return $destination; } } // ------------------------------------------------------------------ // Functions to provide information about a content type function panels_ct_function($type, $name) { if (is_object($type)) { $content_type = $type; } else { $content_type = panels_get_content_type($type); } $function = $content_type[$name]; if (function_exists($function)) { return $function; } } function panels_ct_get_content($type, $conf, $args, $context, $incoming_content) { if ($function = panels_ct_function($type, 'render callback')) { return $function($conf, $args, $context, $incoming_content); } } function panels_ct_get_title($type, $conf) { if ($function = panels_ct_function($type, 'title callback')) { return $function($conf); } } function panels_ct_get_add_form($type, $id, $parents) { if ($function = panels_ct_function($type, 'add callback')) { return $function($id, $parents); } } function panels_ct_validate_add_form($type, $form, $form_values) { if ($function = panels_ct_function($type, 'add validate callback')) { return $function($form, $form_values); } } function panels_ct_submit_add_form($type, $form_values) { if ($function = panels_ct_function($type, 'add submit callback')) { return $function($form_values); } } function panels_ct_get_edit_form($type, $conf, $parents) { if ($function = panels_ct_function($type, 'edit callback')) { return $function($conf, $parents); } } function panels_ct_validate_edit_form($type, $form, $form_values) { if ($function = panels_ct_function($type, 'edit validate callback')) { return $function($form, $form_values); } } function panels_ct_submit_edit_form($type, $form_values) { if ($function = panels_ct_function($type, 'edit submit callback')) { return $function($form_values); } } function panels_ct_get_types($type) { if (is_array($type)) { $content_type = $type; } else { $content_type = panels_get_content_type($type); } $function = $content_type['content_types']; if (is_array($function)) { return $function; } if (function_exists($function)) { return $function($conf); } } /** * Get an array of all available content types that can be fed into the * display editor for the add content list. */ function panels_get_available_content_types($context = NULL, $has_content = FALSE) { $content_types = panels_get_content_types(); // uasort($content_types, 'panels_title_sort'); $available = array(); foreach ($content_types as $id => $type) { // exclude items that require content if we're saying we don't // provide it. if (!empty($type['requires content']) && !$has_content) { continue; } // Check to see if the content type can be used in this context. if (!isset($type['required context']) || (is_array($type['required_context']) && in_array($context, $type['required_context'])) || ($type['required_context'] == $context)) { $available[$id] = panels_ct_get_types($type); } } return $available; } function panels_get_panels($layout, $display) { if (!empty($layout['panels function']) && function_exists($layout['panels function'])) { return $layout['panels function']($display, unserialize($display->layout_settings)); } if (!empty($layout['panels'])) { return $layout['panels']; } return array(); } // ------------------------------------------------------------------ // Functions to provide information about a panel or part of a panel. function panels_get_pane_content($pane, $args = array(), $context = NULL, $incoming_content = '') { if (!$context) { $context = new panels_context; } if (!$incoming_content === '') { $incoming_content = t('Incoming content will be displayed here.'); } return panels_ct_get_content($pane->type, $pane->configuration, $args, $context, $incoming_content); } function panels_get_pane_title($pane) { return panels_ct_get_title($pane->type, $pane->configuration); } function panels_get_pane_edit_form($pane, $parents) { return panels_ct_get_edit_form($pane->type, $pane->configuration, $parents); } function panels_show_pane($pane, $left_buttons, $buttons, $skin = TRUE) { $block = panels_get_pane_content($pane); $title = panels_get_pane_title($pane); $output = theme('panels_pane_dnd', $block, $pane->pid, $title, $left_buttons, $buttons); if ($skin) { $output = '
' . $output . '
'; } return $output; } // --------------------------------------------------------------------------- // panels ajax stuff (part of editing) /** * Simple render function to make sure output is what we want. */ function panels_ajax_render($output = NULL, $title = NULL) { if (!is_object($output)) { $temp = new stdClass(); $temp->output = $output; $temp->type = 'display'; $temp->title = $title; $output = $temp; } if (!$output->output || !$output->type) { $output->output = t('The input was invalid'); $output->type = 'display'; $output->title = t('Error'); } drupal_set_header('Content-Type: text/javascript; charset=utf-8'); print drupal_to_js($output); exit; } /** * entry point into all the ajax stuff */ function panels_ajax($op = NULL, $did = NULL, $pid = NULL) { switch ($op) { case 'submit-form': if ((is_numeric($did) || $did == 'new') && $cache = panels_cache_get($did)) { $output = panels_edit_submit_subform($cache->display); } break; } panels_ajax_render($output); } function panels_ajax_add_content($did = NULL, $panel_id = NULL) { if ((is_numeric($did) || $did == 'new') && $cache = panels_cache_get($did)) { $display = $cache->display; $layout = panels_get_layout($display->layout); $layout_panels = panels_get_panels($layout, $display); if ($layout && array_key_exists($panel_id, $layout_panels)) { $output->output = panels_add_content($cache, $panel_id); $output->type = 'display'; $output->title = t('Add content to !s', array('!s' => $layout_panels[$panel_id])); } } panels_ajax_render($output); } function panels_add_content($cache, $panel_id) { $return->type = 'display'; $return->title = t('Choose type'); panels_set('return', $return); if (!isset($cache->content_types)) { $cache->content_types = panels_get_available_content_types(); } $weights = array(t('Contributed modules') => 0); $categories = array(); $titles = array(); foreach ($cache->content_types as $id => $types) { if (is_array($types)) { foreach ($types as $content_id => $info) { if (isset($info['icon'])) { $icon = $info['icon']; if (isset($info['path'])) { $path = $info['path']; } else { $path = panels_get_path("content_types/$id"); } } else { $icon = 'no-icon.png'; $path = panels_get_path('images'); } $title = filter_xss_admin($info['title']); if (isset($info['description'])) { $description = $info['description']; } else { $description = $title; } if (isset($info['category'])) { if (is_array($info['category'])) { list($category, $weight) = $info['category']; $weights[$category] = $weight; } else { $category = $info['category']; if (!isset($weights['category'])) { $weights[$category] = 0; } } } else { $category = t('Contrib modules'); } $output = '
'; $link_text = theme('image', $path . '/' . $icon, $description, $description); $output .= l($link_text, 'javascript: void()', array('class' => 'panels-modal-add-config', 'id' => $id . '-' . $panel_id . '-' . $content_id), NULL, NULL, NULL, TRUE); $output .= "
$title
"; $output .= '
'; if (!isset($categories[$category])) { $categories[$category] = array(); $titles[$category] = array(); } $categories[$category][] = $output; $titles[$category][] = $title; } } } if (!$categories) { $output = t('There are no content types you may add to this display.'); } else { asort($weights); $output = ''; foreach ($weights as $category => $weight) { $output .= '

' . $category . '

'; $output .= '
'; natcasesort($titles[$category]); foreach ($titles[$category] as $id => $title) { $output .= $categories[$category][$id]; } } } return $output; } function panels_ajax_add_config($did = NULL, $pid = NULL) { if ((is_numeric($did) || $did == 'new') && $cache = panels_cache_get($did)) { $display = $cache->display; list($content_type_id, $panel_id, $type) = explode('-', $pid, 3); $conf = panels_ct_get_add_form($content_type_id, $type, array('configuration')); $types = panels_ct_get_types($content_type_id); $title = $types[$type]['title']; $cache->add_config = array($content_type_id, $conf, $panel_id, $title); panels_cache_set($display->did, $cache); $text = drupal_get_form('panels_add_content_config_form', $cache, $content_type_id, $conf, $panel_id, $title); $output = panels_get('return'); $output->output = $text; } panels_ajax_render($output); } function panels_add_content_config_form($display, $content_type_id = NULL, $conf = NULL, $panel_id = NULL, $title = NULL) { if (empty($content_type_id)) { $cache = panels_cache_get($display->did); if (isset($cache->add_config)) { list($content_type_id, $conf, $panel_id, $title) = $cache->add_config; } } $form['start_form'] = array('#value' => ''); $form['next'] = array( '#type' => 'submit', '#value' => t('Add pane'), ); $return->type = 'display'; $return->title = t('Configure !s', array('!s' => $title)); panels_set('return', $return); return $form; } function panels_add_content_config_form_validate($form_id, $form_values, $form) { panels_ct_validate_add_form($form_values['type'], $form['configuration'], $form_values['configuration']); } function panels_add_content_config_form_submit($form_id, $form) { $cache = panels_cache_get($form['did']); // keep an incrementing counter, add the data to the display. // This counter is so that we can add this pane to the cache but not // make it real until the final 'Save' is clicked. $pid = ++$cache->highest; $form['pid'] = "new-$pid"; $form['access'] = array_keys(array_filter($form['access'])); panels_ct_submit_add_form($form['type'], $form['configuration']); $cache->display->content[$form['pid']] = (object) $form; $cache->display->panels[$form['panel']][] = $form['pid']; // drupal_set_message('
' . var_export($cache->display, true) . '
'); panels_cache_set($form['did'], $cache); // Set info for the javascript so it knows where to put the new pane. // FIXME: Note that ->area appears to be a holdover -- it should be ->panel now. $return->type = 'add'; $return->area = $form['panel']; $return->id = $form['pid']; // we need to fake the buttons a little. $buttons['configure'] = panels_add_button('configure.gif', t('Configure'), t('Configure this pane'), 'pane-configure'); $buttons['configure']['#parents'] = array('button', $form['pid'], 'configure'); $buttons['delete'] = panels_add_button('close.gif', t('Delete'), t('Remove this pane'), 'pane-delete'); $buttons['delete']['#parents'] = array('button', $form['pid'], 'delete'); $buttons = form_builder('dummy', $buttons); // Render the new pane for the javascript. $return->output = panels_show_pane($cache->display->content[$form['pid']], NULL, drupal_render($buttons)); panels_set('return', $return); return FALSE; } function panels_ajax_configure($did = NULL, $pid = NULL) { if ((is_numeric($did) || $did == 'new') && $cache = panels_cache_get($did)) { $text = drupal_get_form('panels_edit_pane_config_form', $cache->display, $pid); $output = panels_get('return'); $output->output = $text; } panels_ajax_render($output); } function panels_edit_pane_config_form($display, $pid = NULL) { $cache = panels_cache_get($display->did); if ($pid === NULL) { if (isset($cache->pid)) { $pid = $cache->pid; } else { return array(); } } else { $cache->pid = $pid; panels_cache_set($display->did, $cache); } $pane = $display->content[$pid]; $form['start_form'] = array('#value' => ''); $form['next'] = array( '#type' => 'submit', '#value' => t('Save'), ); return $form; } function panels_edit_pane_config_form_validate($form_id, $form_values, $form) { panels_ct_validate_edit_form($form_values['type'], $form['configuration'], $form_values['configuration']); } function panels_edit_pane_config_form_submit($form_id, $form) { // save the new configuration. $cache = panels_cache_get($form['did']); panels_ct_submit_edit_form($form['type'], $form['configuration']); $cache->display->content[$form['pid']]->access = array_keys(array_filter($form['access'])); $cache->display->content[$form['pid']]->configuration = $form['configuration']; panels_cache_set($form['did'], $cache); $return->type = 'replace'; $return->id = $form['pid']; $block = panels_get_pane_content($cache->display->content[$form['pid']]); if (!$block->subject) { $block->subject = t('No title'); } $return->output = theme('panels_pane_collapsible', $block, $cache->display); panels_set('return', $return); return FALSE; } function panels_edit_submit_subform($display) { // Check forms to make sure only valid forms can be rendered this way. $valid_forms = array('panels_add_content_config_form', 'panels_edit_pane_config_form'); $form_id = $_POST['form_id']; if (!in_array($form_id, $valid_forms)) { return panels_ajax_render(); } $output = drupal_get_form($form_id, $display); $next = panels_get('next'); if ($next) { $output = drupal_get_form($next['form'], $display, $next['data']); $return = panels_get('return'); if (!$return->output) { $return->output = $output; } } else { if (!($return = panels_get('return'))) { $return->type = 'display'; $return->output = $output; } else if ($return->type == 'display' && !$return->output) { $return->output = $output; } } if ($return->type == 'display') { $return->output = theme('status_messages') . $return->output; } return $return; } // End of ajax functions // --------------------- // --------------------------------------------------------------------------- // panels database functions /** * Forms the basis of a panel display and provides a constructur to ensure * that the display always has a valid context. */ class panels_display { var $args = array(); var $incoming_content = NULL; var $context = NULL; var $css_id = NULL; function panels_display($context = NULL) { if (!isset($context)) { $this->context = new panels_context(); } } } /** * Creates a new display with the given context, so that users don't * have to mess with classes if they don't want to. */ function panels_new_display($context = NULL) { $display = new panels_display($context); $display->did = 'new'; return $display; } /** * Load a display from the database and set a context. */ function panels_load_display($did, $context = NULL) { $display = new panels_display($context); $obj = db_fetch_array(db_query("SELECT * FROM {panels_display} WHERE did = %d", $did)); if (!$obj) { return NULL; } foreach ($obj as $key => $value) { $display->$key = $value; } if (!$display) { return NULL; } $result = db_query("SELECT * FROM {panels_pane} WHERE did = %d ORDER BY panel, position", $did); $display->panels = $display->content = array(); while ($pane = db_fetch_object($result)) { $pane->configuration = unserialize($pane->configuration); $pane->access = ($pane->access ? explode(', ', $pane->access) : array()); $display->panels[$pane->panel][] = $pane->pid; $display->content[$pane->pid] = $pane; } return $display; } /** * Save a display. */ function panels_save_display(&$display) { if ($display->did && $display->did != 'new') { db_query("UPDATE {panels_display} SET layout = '%s', layout_settings = '%s' WHERE did = %d", $display->layout, $display->layout_settings, $display->did); db_query("DELETE FROM {panels_pane} WHERE did = %d", $display->did); } else { $display->did = db_next_id("{panels_display}_id"); db_query("INSERT INTO {panels_display} (did, layout, layout_settings) VALUES (%d, '%s', '%s')", $display->did, $display->layout, $display->layout_settings); } // update all the panes foreach ((array) $display->panels as $id => $panes) { $position = 0; $new_panes = array(); foreach ((array) $panes as $pid) { $pane = $display->content[$pid]; $pane->position = $position++; if (!is_numeric($pid)) { unset($display->content[$pid]); $pane->pid = db_next_id("{panels_pane}_pid"); } db_query("INSERT INTO {panels_pane} (pid, did, panel, type, configuration, access, position) VALUES (%d, %d, '%s', '%s', '%s', '%s', %d)", $pane->pid, $display->did, $pane->panel, $pane->type, serialize($pane->configuration), !empty($pane->access) ? implode(', ', $pane->access) : '', $pane->position); // and put it back so our pids and positions can be used $display->content[$pid] = $pane; $new_panes[] = $pid; } $display->panels[$id] = $panes; } return $display; // to be nice, even tho we have a reference. } /** * Delete a display */ function panels_delete_display($display) { db_query("DELETE FROM {panels_display} WHERE did = %d", $display->did); db_query("DELETE FROM {panels_pane} WHERE did = %d", $display->did); } /** * For external use: Given a layout ID and a $content array, return the * panel display. The content array is filled in based upon the content * available in the layout. If it's a two column with a content * array defined like array('left' => t('Left side'), 'right' => * t('Right side')), then the $content array should be array('left' => * $output_left, 'right' => $output_right) */ function panels_print_layout($id, $content) { $layout = panels_get_layout($id); if (!$layout) { return; } return panels_render_layout($layout, $content); } /** * Given a full layout structure and a content array, render a panel display. */ function panels_render_layout($layout, $content, $css_id = NULL, $settings = array()) { $output = theme($layout['theme'], check_plain($css_id), $content, $settings); if ($output) { if (file_exists(path_to_theme() . '/' . $layout['css'])) { drupal_add_css(path_to_theme() . '/' . $layout['css']); } else { drupal_add_css(panels_get_path($layout['css'], false, $layout['module'])); } } return $output; } class panels_context { var $type = NULL; var $data = NULL; function panels_context($type = 'none', $data = NULL) { $this->type = $type; $this->data = $data; } } /** * Clean up a display and make sure it has some required information if * it doesn't already exist. Currently we wrequire a context, an incoming * content and a css_id. */ function panels_sanitize_display(&$display) { if (!isset($display->args)) { $display->args = array(); } if (!isset($display->incoming_content)) { $display->incoming_content = NULL; } if (!isset($display->context)) { $display->context = new panels_context(); } if (!isset($display->css_id)) { $display->css_id = NULL; } } /** * Render a display by loading the content into an appropriate * array and then passing through to panels_render_layout. * * if $incoming_content is NULL, default content will be applied. Use * an empty string to indicate no content. */ function panels_render_display(&$display) { $layout = panels_get_layout($display->layout); if (!$layout) { return NULL; } panels_sanitize_display($display); foreach ($display->content as $pid => $pane) { if ($result = panels_get_pane_content($pane, $display->args, $display->context, $display->incoming_content)) { if (!empty($content[$pane->panel])) { $content[$pane->panel] .= theme('panels_separator', $display); } if (panels_pane_access($pane)) { $content[$pane->panel] .= theme('panels_pane', $result, $display); } } } $output = panels_render_layout($layout, $content, $display->css_id, unserialize($display->layout_settings)); return $output; } // --------------------------------------------------------------------------- // panels data loading function panels_load_includes($directory, $callback, $file = NULL) { // Load all our module 'on behalfs'. $path = panels_get_path($directory); $files = drupal_system_listing("$file" . '.inc$', $path, 'name', 0); foreach($files as $file) { require_once('./' . $file->filename); } $output = module_invoke_all($callback); foreach ($files as $file) { $function = 'panels_' . $file->name . '_' . $callback; if (function_exists($function)) { $result = $function(); if (isset($result) && is_array($result)) { $output = array_merge($output, $result); } } } return $output; } function panels_get_layout($layout) { return panels_get_layouts($layout); } function panels_get_layouts($layout = NULL) { static $layouts = array(); static $all_layouts = FALSE; if (!$all_layouts) { if (!$layout) { $layouts = panels_load_includes('layouts', 'panels_layouts'); $all_layouts = TRUE; } else if (!array_key_exists($layout, $layouts)) { $temp_layouts = panels_load_includes('layouts', 'panels_layouts', $layout); if (isset($temp_layouts[$layout])) { $layouts[$layout] = $temp_layouts[$layout]; } } } if ($layout) { return isset($layouts[$layout]) ? $layouts[$layout] : NULL; } return $layouts; } function panels_get_content_type($content_type) { return panels_get_content_types($content_type); } function panels_get_content_types($content_type = NULL) { static $content_types = array(); static $all_content_types = FALSE; if (!$all_content_types) { if (!$content_type) { $content_types = panels_load_includes('content_types', 'panels_content_types'); $all_content_types = TRUE; } else if (!array_key_exists($content_type, $content_types)) { $temp_content_types = panels_load_includes('content_types', 'panels_content_types', $content_type); if (isset($temp_content_types[$content_type])) { $content_types[$content_type] = $temp_content_types[$content_type]; } } } if ($content_type) { return isset($content_types[$content_type]) ? $content_types[$content_type] : NULL; } return $content_types; } /** * Includes required JavaScript libraries: * jQuery, iutil, idrag, idrop, isortables * In addition to panels.js. */ function _panels_js_files() { // while we don't use this directly some of our forms do. drupal_add_js('misc/collapse.js'); drupal_add_js('misc/autocomplete.js'); drupal_add_js(panels_get_path('js/lib/dimensions.js')); drupal_add_js(panels_get_path('js/lib/mc.js')); drupal_add_js(panels_get_path('js/lib/form.js')); drupal_add_js(array('panelsAjaxURL' => url('panels/ajax', NULL, NULL, TRUE)), 'setting'); drupal_add_js(panels_get_path('js/display_editor.js')); drupal_add_css(panels_get_path('css/panels_dnd.css')); drupal_add_css(panels_get_path('css/panels_admin.css')); } // --------------------------------------------------------------------------- // Panels theming functions function theme_panels_dnd($content) { $output = "
$content
"; return $output; } function theme_panels_panel_dnd($content, $area, $label, $footer) { return "
$footer

$label

$content
"; } function theme_panels_pane_dnd($block, $id, $label, $left_buttons = NULL, $buttons = NULL) { if (!$block->subject) { $block->subject = t('No title'); } static $count = 0; $output .= "
"; if ($buttons) { $output .= "$buttons"; } if ($left_buttons) { $output .= "$left_buttons"; } $output .= "$label
"; $output .= '
'; $output .= theme('panels_pane_collapsible', $block); $output .= '
'; return $output; } function theme_panels_pane($block, $display) { $output = '
'; $output .= theme('block', $block); $output .= '
'; return $output; } function theme_panels_pane_collapsible($block) { $output .= '

' . $block->subject . '

'; $output .= '
' . filter_xss_admin($block->content) . '
'; return $output; } function theme_panels_separator($display) { return '
'; } /** * Print the layout link. Sends out to a theme function. */ function panels_print_layout_link($id, $layout, $link) { drupal_add_css(panels_get_path('css/panels_admin.css')); $file = panels_get_path($layout['icon'], false, $layout['module']); $image = l(theme('image', $file), $link, NULL, NULL, NULL, NULL, TRUE); $title = l($layout['title'], $link); return theme('panels_layout_link', $title, $id, $image, $link); } function panels_print_layout_icon($id, $layout, $title = NULL) { drupal_add_css(panels_get_path('css/panels_admin.css')); $file = panels_get_path($layout['icon'], false, $layout['module']); return theme('panels_layout_icon', $id, theme('image', $file), $title); } /** * Theme the layout link image */ function theme_panels_layout_link($title, $id, $image, $link) { $output .= ''; return $output; } /** * Theme the layout icon image */ function theme_panels_layout_icon($id, $image, $title = NULL) { $output .= '
'; $output .= $image; if ($title) { $output .= '
' . $title . '
'; } $output .= '
'; return $output; } /** * This is separate because it must be outside the
to work, and * everything in the form theme is inside the form. */ function theme_panels_hidden() { // TODO: Move this to a theme function. $close_text = t('Close Window'); $close_image = theme('image', panels_get_path('images/close.gif'), t('Close window'), t('Close window')); $throbber_image = theme('image', panels_get_path('images/throbber.gif'), t('Loading...'), t('Loading')); $output = <<\n
\n
\n \n \n
\n
\n
\n
$throbber_image\n
\n \n EOF; return $output; } /** * Helper function for autocompletion of node titles. * This is mostly stolen from clipper. */ function panels_node_autocomplete($string) { if ($string != '') { // if there are node_types passed, we'll use those in a MySQL IN query. $result = db_query_range(db_rewrite_sql('SELECT n.title, u.name FROM {node} n INNER JOIN {users} u ON u.uid = n.uid WHERE LOWER(title) LIKE LOWER("%%%s%%")'), $string, 0, 10); $prefix = count($array) ? implode(', ', $array) .', ' : ''; $matches = array(); while ($node = db_fetch_object($result)) { $n = $node->title; // Commas and quotes in terms are special cases, so encode 'em. if (preg_match('/,/', $node->title) || preg_match('/"/', $node->title)) { $n = '"'. preg_replace('/"/', '""', $node->title) .'"'; } $matches[$prefix . $n] = ''. check_plain($node->title) .' ('. t('by %user', array('%user' => check_plain($node->name))) .')'; } drupal_set_header('Content-Type: text/javascript; charset=utf-8'); print drupal_to_js($matches); exit(); } } /** * function for uasort to do title sorting. */ function panels_title_sort($a, $b) { if (!isset($a['weight'])) { $a['weight'] = 0; } if (!isset($b['weight'])) { $b['weight'] = 0; } if (!isset($a['title'])) { $a['title'] = NULL; } if (!isset($b['title'])) { $b['title'] = NULL; } if ($a['weight'] == $b['weight']) { if ($a['title'] < $b['title']) { return -1; } else if (drupal_strtolower($a['title']) > drupal_strtolower($b['title'])) { return 1; } else { return 0; } } return ($a['weight'] < $b['weight']) ? -1 : 1; }