panels_ajax_tab.module in Panels Ajax Tabs 7
Allows users to create and manage Panels Ajax Tabs.
File
panels_ajax_tab.moduleView source
<?php
/**
* @file
* Allows users to create and manage Panels Ajax Tabs.
*/
/**
* Implements hook_ctools_plugin_api().
*/
function panels_ajax_tab_ctools_plugin_api() {
return array(
"version" => "1",
);
}
/**
* Implements hook_ctools_plugin_dierctory().
*/
function panels_ajax_tab_ctools_plugin_directory($module, $plugin) {
if ($plugin == 'content_types') {
return 'plugins/' . $plugin;
}
}
/**
* Implements hook_menu().
*/
function panels_ajax_tab_menu() {
$items = array();
$items['panels_ajax_tab/%/%/%'] = array(
'title' => 'panels-ajax tab AJAX callback',
'description' => 'AHAJ callback for panels tabs',
'page callback' => 'panels_ajax_tab_ajax',
'page arguments' => array(
1,
2,
3,
),
'access arguments' => array(
'access content',
),
'type' => MENU_CALLBACK,
);
$items['admin/config/user-interface/panels-ajax-tab'] = array(
'title' => 'Panels AJAX Tabs Visibility',
'description' => "Configure visibility rule for panels ajax tab.",
'page callback' => 'panels_ajax_tab_admin_overview',
'access arguments' => array(
'administer site configuration',
),
'file' => 'panels_ajax_tab.admin.inc',
);
$items['admin/config/user-interface/panels-ajax-tab/%panels_ajax_tab_container/edit'] = array(
'description' => 'Visibility settings callback for panels tabs',
'title' => 'panels-ajax tab visibility settings',
'title callback' => '_panels_ajax_tab_settings_title',
'title arguments' => array(
4,
),
'page callback' => 'drupal_get_form',
'page arguments' => array(
'panels_ajax_tab_settings',
4,
),
'access arguments' => array(
'administer site configuration',
),
'file' => 'panels_ajax_tab.admin.inc',
'type' => MENU_NORMAL_ITEM,
);
return $items;
}
/**
* Title callback: Returns a title for Panel AJAX tab container.
*
* @param array $panels_ajax_tab
* An panels ajax tab configuration.
*/
function _panels_ajax_tab_settings_title(array $panels_ajax_tab) {
return t('@container_id settings', array(
'@container_id' => $panels_ajax_tab['container_id'],
));
}
/**
* Loads a panels ajax tab configuration.
*
* @param string $container_id
* The container id.
*/
function panels_ajax_tab_container_load($container_id) {
if (!empty($container_id)) {
$panels_ajax_tabs = panels_ajax_tab_config_cache();
foreach ($panels_ajax_tabs as $panels_ajax_tab) {
if ($panels_ajax_tab['container_id'] == $container_id) {
return $panels_ajax_tab;
}
}
}
return FALSE;
}
/**
* Implements hook_theme().
*/
function panels_ajax_tab_theme($existing, $type, $theme, $path) {
return array(
'panels_ajax_tab_tabs' => array(
'variables' => array(
'tabs' => array(),
'tab_container_id' => NULL,
'context_string' => NULL,
'clean_url' => FALSE,
'clean_url_delim' => '/',
),
),
'panels_ajax_tab_container' => array(
'variables' => array(
'tab_container_id' => NULL,
'preloaded' => '',
'content' => '',
),
),
'panels_ajax_tab_ajax' => array(
'variables' => array(
'minipanel' => NULL,
),
),
'panels_ajax_tab_tabs_edit_form' => array(
'render element' => 'form',
),
);
}
/**
* Implements hook_boot().
*
* IF Clean-URLs are enabled for any ajax-tab pane, we strip the URL identifier
* off the end of the URL and place it in $_GET['panels_ajax_tab_trigger'].
* We additionally put the mini-panel this corresponds to in
* $_GET['panels_ajax_tab_tab']. Once this is done drupal can handle the URL
* normally (it won't get confused by the identifier on the end of the URL) and
* panels-ajax-tabs will look for what tab to load by inspecting
* $_GET['panels_ajax_tab_tab']. In Essense, it transforms a url like
* http://example.com/path/to/drupal/page.mytab to a url like
* http://example.com/path/to/drupal/page?panels_ajax_tab_trigger=mytab&panels_ajax_tab_tab=mypanel.
*/
function panels_ajax_tab_boot() {
$config_cache = cache_get('panels_ajax_tab_config_cache');
// If there are no url-cache settings, ensure that the url-cache is rebuilt
// for next-time and skip.
if (empty($config_cache)) {
register_shutdown_function('panels_ajax_tab_config_cache');
return;
}
foreach ($config_cache->data as $config) {
if ($config['clean_url']) {
foreach ($config['mini_panels'] as $panel_id => $panel_conf) {
$delim = $config['clean_url_delim'];
$trigger = $delim . $panel_conf['url_id'];
$pathlen = strlen($_GET['q']);
$triggerlen = strlen($trigger);
if ($triggerlen > $pathlen) {
continue;
}
if (substr_compare($_GET['q'], $trigger, -$triggerlen) === 0) {
$_GET['q'] = substr($_GET['q'], 0, $pathlen - $triggerlen);
$_GET['panels_ajax_tab_tab'] = $panel_id;
$_GET['panels_ajax_tab_trigger'] = $panel_conf['url_id'];
return;
}
}
}
}
}
/**
* Implements hook_element_info_alter().
*
* Form actions should default to the panels-ajax-tab request URL, not the
* actual request URI.
*/
function panels_ajax_tab_element_info_alter(&$element_info) {
if (arg(0) == 'panels_ajax_tab') {
$headers = getallheaders();
if (!empty($headers['X-Request-Path'])) {
$element_info['form']['#action'] = $headers['X-Request-Path'];
}
}
}
/**
* AJAX callback for rendering tab.
*/
function panels_ajax_tab_ajax($panel_name, $context_string, $url_enabled) {
// Modify the request so downstream modules properly process the URL
// and menu object.
$headers = getallheaders();
if (!empty($headers['X-Request-Path'])) {
$_GET['original_q'] = $_GET['q'];
$_GET['q'] = ltrim($headers['X-Request-Path'], '/');
panels_ajax_tab_boot();
$_GET['q'] = drupal_get_normal_path($_GET['q']);
}
// Load the mini panel.
$mini = panels_ajax_tab_prepare_mini($panel_name, $context_string);
// Render the output.
$output = theme('panels_ajax_tab_ajax', array(
'minipanel' => $mini,
'url_enabled' => $url_enabled,
));
$response = array();
$response['markup'] = $output;
// Allow other modules to alter the response.
$trigger = !empty($_GET['panels_ajax_tab_trigger']) ? $_GET['panels_ajax_tab_trigger'] : '';
drupal_alter('panels_ajax_tab_response', $response, $panel_name, $context_string, $trigger);
drupal_json_output($response);
exit;
}
/**
* Prepares the mini-panel.
*/
function panels_ajax_tab_prepare_mini($mini, $context_string) {
ctools_include('context');
ctools_include('plugins');
ctools_include('plugins', 'panels');
if (is_string($mini)) {
$mini = panels_mini_load($mini);
}
if ($context_string != 'none') {
$entity = panels_ajax_tab_get_context($context_string);
if (!$entity) {
drupal_not_found();
exit;
}
// If it's a node, check node-view permissions.
if ($entity->entity_type == 'node') {
if (!node_access('view', $entity)) {
drupal_access_denied();
exit;
}
}
$context_plugin = ctools_get_plugins('ctools', 'contexts', 'entity');
$context_plugin['keyword'] = $entity->entity_type;
$context = ctools_context_create_entity(FALSE, $entity, FALSE, $context_plugin);
// Load up any contexts we might be using.
$context = ctools_context_match_required_contexts($mini->requiredcontexts, array(
$context,
));
$mini->context = $mini->display->context = ctools_context_load_contexts($mini, FALSE, $context);
}
if (empty($mini) || !empty($mini->disabled)) {
return;
}
$mini->display->owner = $mini;
// Unique ID of this mini.
$mini->display->owner->id = $mini->name;
return $mini;
}
/**
* Get a context from a context_string.
*/
function panels_ajax_tab_get_context($context_string) {
if (empty($context_string) || $context_string == 'none') {
return FALSE;
}
$parts = explode(':', $context_string);
$entity_type = strtolower($parts[0]);
$entity_ids = array(
(int) $parts[1],
);
$entities = entity_load($entity_type, $entity_ids);
$entity = array_pop($entities);
$entity->entity_type = $entity_type;
return $entity;
}
/**
* Theme function that renders the panels ajax tabs.
*/
function theme_panels_ajax_tab_tabs($vars) {
foreach ($vars['tabs'] as $tab) {
$url_enabled = isset($tab['url_enabled']) ? $tab['url_enabled'] : 1;
$tabhtml = '<a href="' . $tab['href'] . '" class="panels-ajax-tab-tab" data-panel-name="' . $tab['mini_panel']->name . '" data-target-id="' . $vars['tab_container_id'] . '" data-entity-context="' . $vars['context_string'] . '" data-trigger="' . $tab['url_id'] . '" data-url-enabled="' . $url_enabled . '">' . $tab['title'] . '</a>';
// Add a hidden link for javascript enabled crawlers (but not normal web
// crawlers).
$tabhtml .= '<a href="/panels_ajax_tab/' . $tab['mini_panel']->name . '/' . $vars['context_string'] . '/' . $url_enabled . '" rel="nofollow" style="display:none" class="js-crawler-link"></a>';
$tabs[] = $tabhtml;
}
return theme('item_list', array(
'items' => $tabs,
'attributes' => array(
'class' => array(
'tabs',
'inline',
'panels-ajax-tab',
),
),
));
}
/**
* Theme function that renders the container.
*/
function theme_panels_ajax_tab_container($vars) {
return '<div data-panels-ajax-tab-preloaded="' . $vars['preloaded'] . '" id="panels-ajax-tab-container-' . $vars['tab_container_id'] . '" class="panels-ajax-tab-container">' . $vars['content'] . '</div>';
}
/**
* Theme function that renders the AHAH markup for a mini-panel.
*/
function theme_panels_ajax_tab_ajax($vars) {
// Grab all CSS for later comparison before clearing it.
$previous_css = drupal_add_css();
// Clear the JavaScript & CSS not related to the pane being rendered.
drupal_static_reset('drupal_add_js');
drupal_static_reset('drupal_add_css');
// Render the pane.
$mini = $vars['minipanel'];
$layout = panels_get_layout($mini->display->layout);
if (empty($mini->display->cache_key)) {
$mini->display->cache_key = $mini->name;
}
$panels_output = panels_render_display($mini->display);
// Grab new CSS files related to this pane.
$css = drupal_add_css();
// Assign a unique basename to new stylesheets.
foreach ($css as $key => $item) {
if ($item['type'] == 'file') {
// If not defined, force a unique basename for this file.
$basename = isset($item['basename']) ? $item['basename'] : drupal_basename($item['data']);
$item['basename'] = $basename;
$css[$key] = $item;
}
}
// Iterate through previous CSS stylesheets, and add any with matching
// basenames to allow, for proper overrides when calling drupal_get_css($css).
foreach ($previous_css as $key => $item) {
if ($item['type'] == 'file') {
// If not defined, force a unique basename for this file.
$basename = isset($item['basename']) ? $item['basename'] : drupal_basename($item['data']);
$item['basename'] = $basename;
$previous_css[$key] = $item;
foreach ($css as $key2 => $item2) {
// Make sure to append previous stylesheets with matching basenames
// to the new CSS array.
if ($item['basename'] == $item2['basename']) {
$css[$key] = $previous_css[$key];
}
}
}
}
$output = '';
$output .= '<?xml version="1.0" encoding="UTF-8" ?>';
$output .= '
<html version="HTML+RDFa+MathML 1.1"
xmlns:content="http://purl.org/rss/1.0/modules/content/"
xmlns:dc="http://purl.org/dc/terms/"
xmlns:foaf="http://xmlns.com/foaf/0.1/"
xmlns:og="http://ogp.me/ns#"
xmlns:rdfs="http://www.w3.org/2000/01/rdf-schema#"
xmlns:sioc="http://rdfs.org/sioc/ns#"
xmlns:sioct="http://rdfs.org/sioc/types#"
xmlns:skos="http://www.w3.org/2004/02/skos/core#"
xmlns:xsd="http://www.w3.org/2001/XMLSchema#"
xmlns:mml="http://www.w3.org/1998/Math/MathML">
';
$output .= '<head>';
// Need to call page alter so that modules like google analytics can add js
// We only invoke the page alter if url_enabled is true.
if ($vars['url_enabled']) {
$page = array();
drupal_alter('page', $page);
}
// Get the javascript and filter out the default misc/drupal.js -
// it's already been added by the calling page.
$javascript = drupal_add_js();
unset($javascript['misc/drupal.js']);
// Add the javascript.
$output .= drupal_get_js('header', $javascript);
// Add CSS.
$output .= drupal_get_css($css);
if (isset($layout['css'])) {
$output .= "<link rel='stylesheet' type='text/css' href='" . base_path() . $layout['path'] . '/' . $layout['css'] . "' />";
}
$output .= '</head>';
// Print the output of the panel.
$output .= '<body>';
$output .= theme('status_messages');
$output .= '<div class="panels-ajax-tab-panel panels-ajax-tab-panel-' . str_replace('_', '-', $mini->name) . '">';
$output .= $panels_output;
$output .= '</div>';
$output .= drupal_get_js('footer', $javascript);
$output .= '</body></html>';
return $output;
}
/**
* Theme function that renders the pane configuration form.
*/
function theme_panels_ajax_tab_tabs_edit_form($variables) {
$form = $variables['form'];
$output = '';
// Render elements that are supposed to be on top.
foreach (element_children($form) as $element) {
if ($element == 'mini_panels') {
break;
}
else {
$output .= drupal_render($form[$element]);
}
}
$rows = array();
foreach (element_children($form['mini_panels']) as $mini_panel) {
$form['mini_panels'][$mini_panel]['weight']['#attributes']['class'] = array(
'panel-weight',
);
$rows[] = array(
'data' => array(
drupal_render($form['mini_panels'][$mini_panel]['selected']),
drupal_render($form['mini_panels'][$mini_panel]['name']),
drupal_render($form['mini_panels'][$mini_panel]['tab_title']),
drupal_render($form['mini_panels'][$mini_panel]['url_id']),
drupal_render($form['mini_panels'][$mini_panel]['weight']),
),
'class' => array(
'draggable',
),
);
}
$header = array(
t('Select'),
t('Mini panel'),
t('Tab title'),
t('URL identifier'),
t('Weight'),
);
$output .= theme('table', array(
'header' => $header,
'rows' => $rows,
'attributes' => array(
'id' => 'panels-ajax-tab-admin-table',
),
));
$output .= drupal_render_children($form);
drupal_add_tabledrag('panels-ajax-tab-admin-table', 'order', 'sibling', 'panel-weight');
return $output;
}
/**
* Implements hook_flush_caches().
*/
function panels_ajax_tab_flush_caches() {
// After caches are cleared we will run panels_ajax_tab_config_cache
// to immediately rebuild the url-cache.
register_shutdown_function('panels_ajax_tab_config_cache');
// We don't want to add any custom cache-tables, just return an empty array.
return array();
}
/**
* Implements hook_cron().
*/
function panels_ajax_tab_cron() {
panels_ajax_tab_config_cache();
}
/**
* Rebuild the URL cache.
*
* URL suffix information is needed on boot, but it cannot be generated at boot
* time, so we generate it separately and store
* it in a cache item.
*/
function panels_ajax_tab_config_cache() {
$configs = panels_ajax_tab_get_config();
cache_set('panels_ajax_tab_config_cache', $configs);
return $configs;
}
/**
* Get a list of all panels-ajax-tab configs.
*
* This is used to build a list url suffixes to process at boot if so enabled.
*/
function panels_ajax_tab_get_config() {
$config = array();
// Mini panels.
if (module_exists('panels_mini')) {
$panels = panels_mini_load_all();
foreach ($panels as $panel) {
if (!empty($panel->display->content)) {
foreach ($panel->display->content as $pid => $pane) {
if (in_array($pane->type, array(
'panels_ajax_tab_tabs',
'highwire_panel_tabs',
))) {
$pane->configuration['plugin_type'] = $pane->type;
$container_id = $pane->configuration['container_id'];
$config[$container_id] = $pane->configuration;
}
}
}
}
}
// Page-manager pages.
if (module_exists('page_manager')) {
// Now check all panel pages and ignore all mini panels.
ctools_include('page', 'page_manager', 'plugins/tasks');
ctools_include('page_manager.admin', 'page_manager', '');
ctools_include('export');
$tasks = page_manager_get_tasks_by_type('page');
$pages = array();
foreach ($tasks as $task) {
if ($task_pages = page_manager_load_task_handlers($task)) {
$pages = array_merge($pages, $task_pages);
}
if ($subtasks = page_manager_get_task_subtasks($task)) {
foreach ($subtasks as $subtask) {
$task_pages = page_manager_load_task_handlers($subtask);
$pages = array_merge($pages, $task_pages);
}
}
}
// Not all display objects are loaded, make sure to load them.
foreach ($pages as $page) {
if (empty($page->conf['display']) && !empty($page->conf['did'])) {
$page->conf['display'] = panels_load_display($page->conf['did']);
}
}
foreach ($pages as $page) {
if (empty($page->disabled) && !empty($page->conf['display']->content)) {
foreach ($page->conf['display']->content as $pid => $pane) {
if (in_array($pane->type, array(
'panels_ajax_tab_tabs',
'highwire_panel_tabs',
))) {
$pane->configuration['plugin_type'] = $pane->type;
$container_id = $pane->configuration['container_id'];
$config[$container_id] = $pane->configuration;
}
}
}
}
}
// Post-process the configurations.
$old_settings = variable_get('panels_ajax_tab', array(
'clean_url' => FALSE,
'clean_url_delim' => '/',
'panes' => array(),
));
// Get the visibility settings, if available.
$visibility_rules = variable_get('panels_ajax_tab_visibility_rules', array());
foreach ($config as &$conf) {
// Remove any unselected mini-panels from the config.
foreach ($conf['mini_panels'] as $panel_id => $panel_conf) {
if (!$panel_conf['selected']) {
unset($conf['mini_panels'][$panel_id]);
}
}
// Sort remaining panels.
uasort($conf['mini_panels'], 'drupal_sort_weight');
// Mix in any missing settings. Some settings could be missing due to
// upgrade path.
if (!isset($conf['clean_url'])) {
$conf['clean_url'] = $old_settings['clean_url'];
}
if (!isset($conf['clean_url_delim'])) {
$conf['clean_url_delim'] = $old_settings['clean_url_delim'];
}
// Add up visibility.
$visibility_settings = !empty($visibility_rules[$conf['container_id']]) ? $visibility_rules[$conf['container_id']] : array();
$conf['visibility_settings'] = !empty($conf['visibility_settings']) ? $conf['visibility_settings'] : $visibility_settings;
}
// This goes in an alter hook.
$old_settings = variable_get('panels_ajax_tab', array(
'clean_url' => FALSE,
'clean_url_delim' => '/',
'panes' => array(),
));
foreach ($config as &$conf) {
if (!isset($conf['highwire_panel_tab']) && !empty($old_settings['highwire_panel_tab'])) {
$conf['highwire_panel_tab'] = $old_settings['highwire_panel_tab'];
}
}
return $config;
}
/**
* Helper function to get the visibility per container, if any.
*/
function _panels_ajax_tab_get_container_visibility_settings($container_id) {
$tab_visibility_config =& drupal_static(__FUNCTION__);
if (!isset($tab_visibility_config[$container_id])) {
$tab_visibility_config[$container_id] = array();
// Find the panel_tabs configuration associated with this container.
$config_cache = cache_get('panels_ajax_tab_config_cache');
if (!empty($config_cache)) {
$configs = $config_cache->data;
}
else {
$configs = panels_ajax_tab_config_cache();
}
foreach ($configs as $config) {
if ($config['container_id'] == $container_id) {
$tab_visibility_config[$container_id] = !empty($config['visibility_settings']) ? $config['visibility_settings'] : array();
break;
}
}
}
return $tab_visibility_config[$container_id];
}
/**
* Determine if the current user has access via plugin.
*/
function panels_ajax_tab_ctools_access($mini_panel, $visibility_settings, $contexts) {
if (empty($contexts) || empty($visibility_settings)) {
return TRUE;
}
$panels_ajax_tab_access =& drupal_static(__FUNCTION__);
$cache_arg = array(
$mini_panel,
$visibility_settings,
$contexts,
);
$cache_key = __FUNCTION__ . '_' . md5(serialize($cache_arg));
if (!isset($panels_ajax_tab_access[$cache_key])) {
$panels_ajax_tab_access[$cache_key] = TRUE;
$contexts = !is_array($contexts) ? array(
$contexts,
) : $contexts;
$new_contexts = array();
foreach ($contexts as $key => $context) {
$new_contexts[$context->id] = $context;
}
if (isset($visibility_settings[$mini_panel])) {
$visibility_setting = $visibility_settings[$mini_panel];
if (!empty($visibility_setting['visibility_rule']) && $visibility_setting['visibility_rule'] != 'none') {
$setting = array();
$setting['name'] = $visibility_setting['visibility_rule'];
$setting['settings'] = $visibility_setting['visibility_settings'];
$setting['not'] = $visibility_setting['visibility_settings']['not'];
$setting['context'] = $context->id;
$settings['plugins'] = array(
$setting,
);
ctools_include('context');
$panels_ajax_tab_access[$cache_key] = ctools_access($settings, $new_contexts);
}
}
}
return $panels_ajax_tab_access[$cache_key];
}
/**
* If we are running nginx we need to implement getallheaders our self.
*
* Code is taken from http://php.net/manual/en/function.getallheaders.php.
*/
if (!function_exists('getallheaders')) {
/**
* Fetch all HTTP request headers.
*/
function getallheaders() {
foreach ($_SERVER as $name => $value) {
if (substr($name, 0, 5) == 'HTTP_') {
$headers[str_replace(' ', '-', ucwords(strtolower(str_replace('_', ' ', substr($name, 5)))))] = $value;
}
}
return $headers;
}
}
Functions
Name![]() |
Description |
---|---|
panels_ajax_tab_ajax | AJAX callback for rendering tab. |
panels_ajax_tab_boot | Implements hook_boot(). |
panels_ajax_tab_config_cache | Rebuild the URL cache. |
panels_ajax_tab_container_load | Loads a panels ajax tab configuration. |
panels_ajax_tab_cron | Implements hook_cron(). |
panels_ajax_tab_ctools_access | Determine if the current user has access via plugin. |
panels_ajax_tab_ctools_plugin_api | Implements hook_ctools_plugin_api(). |
panels_ajax_tab_ctools_plugin_directory | Implements hook_ctools_plugin_dierctory(). |
panels_ajax_tab_element_info_alter | Implements hook_element_info_alter(). |
panels_ajax_tab_flush_caches | Implements hook_flush_caches(). |
panels_ajax_tab_get_config | Get a list of all panels-ajax-tab configs. |
panels_ajax_tab_get_context | Get a context from a context_string. |
panels_ajax_tab_menu | Implements hook_menu(). |
panels_ajax_tab_prepare_mini | Prepares the mini-panel. |
panels_ajax_tab_theme | Implements hook_theme(). |
theme_panels_ajax_tab_ajax | Theme function that renders the AHAH markup for a mini-panel. |
theme_panels_ajax_tab_container | Theme function that renders the container. |
theme_panels_ajax_tab_tabs | Theme function that renders the panels ajax tabs. |
theme_panels_ajax_tab_tabs_edit_form | Theme function that renders the pane configuration form. |
_panels_ajax_tab_get_container_visibility_settings | Helper function to get the visibility per container, if any. |
_panels_ajax_tab_settings_title | Title callback: Returns a title for Panel AJAX tab container. |