contrib modules security updates

This commit is contained in:
Bachir Soussi Chiadmi
2016-10-13 12:10:40 +02:00
parent ffd758abc9
commit 747127f643
732 changed files with 67976 additions and 23207 deletions

View File

@@ -1,6 +1,3 @@
Welcome to Panels 3
Welcome to Panels 3.
A little documentation should go here, but Panels 3 is alsoi a beast - you're
best off checking the online handbook on Drupal.org, or this issue:
http://drupal.org/node/887560.
Documentation is available at https://www.drupal.org/node/496278

View File

@@ -11,7 +11,7 @@ Upgrading from Panels-6.x-3.x to Panels-7.x-3.x
- panels_plugin_get_function() deprecated.
- panels_required_context removed. These were deprecated long ago and
- panels_required_context removed. These were deprecated long ago and
existed only to prevent crashes.
- panels_optional_context removed.
@@ -20,3 +20,13 @@ Upgrading from Panels-6.x-3.x to Panels-7.x-3.x
- display_renderer class is now in 'renderer', not 'handler'.
Upgrading task handlers from Panels 7.x-3.5 or older to Panels 7.x-3.6 and newer:
- You must specify a storage type for any panels display using your custom task handler.
For examples, see panels_update_7306.
- When creating whatever stores the panel, a storage id and storage type must be defined.
See panels_mini.module for examples inside panels_mini_save and panels_mini_panels_cache_get.
- A display access plugin must be defined.
See panels_mini/plugins/panels_storage/panels_mini.inc for an example plugin.

View File

@@ -40,11 +40,6 @@ div.panel-pane:hover div.panel-hide {
margin-top: -1.5em;
}
div.panel-pane div.node {
margin: 0;
padding: 0;
}
div.panel-pane div.feed a {
float: right;
}

View File

@@ -175,7 +175,7 @@ div.panels-set-title-hide .panel-pane-is-title {
margin: 0;
}
.panel-portlet .buttons input {
.panel-portlet .buttons input, .panel-portlet .buttons button {
margin: 0;
padding: 0;
display: inline;
@@ -305,11 +305,19 @@ a.close img {
background: url(../images/bg-content-modal.png);
height: 100%;
margin: -1em;
padding-top: 1em;
padding-bottom: 1em;
padding-left: 175px;
position: relative;
}
.panels-section-columns-quickfilter {
padding-top: 1em;
padding-left: 1em;
padding-bottom: 1em;
margin-bottom: 1em;
background-color: #EEEEEE;
}
.panels-section-columns {
height: 100%;
overflow: auto;
@@ -369,22 +377,29 @@ a.close img {
text-align: left;
}
.content-type-button a {
display: inline-block;
width: 99%;
}
.content-type-button a:focus {
border: 1px dotted black;
}
.content-type-button img {
border: 2px solid white;
float: left;
}
.content-type-button img:hover {
border: 2px solid blue;
}
.content-type-button div {
.content-type-button div,
.content-type-button span {
width: 85%;
position: relative;
top: -5px;
left: 2px;
float: left;
padding-left: 3px;
padding-top: 5px;
left: 3px;
}
#panels-preview .modal-throbber-wrapper {

View File

@@ -48,7 +48,7 @@ The include file defines all the other files that our layout will utilize in ord
<ol>
<li><strong>Title:</strong><br />The title of our layout. (Utilized within the panels administration screens)</li>
<li><strong>Icon:</strong><br />The graphical representation of our layout. (Utilized within the panels administration screens)</li>
<li><strong>Theme:</strong><br />The template file of our layout. (Sharp eyed readers will note that the theme definition utilizes underscores instead of dashes, and does not have ".tpl.php" after it. This is refering to the layout-sample-first-layout.tpl.php file all the same, it is simply how the naming convention works. Utilize dashes in the tpl file name and underscores when refering to it in your include file.)</li>
<li><strong>Theme:</strong><br />The template file of our layout. (Sharp eyed readers will note that the theme definition utilizes underscores instead of dashes, and does not have ".tpl.php" after it. This is referring to the layout-sample-first-layout.tpl.php file all the same, it is simply how the naming convention works. Utilize dashes in the tpl file name and underscores when referring to it in your include file.)</li>
<li><strong>CSS:</strong><br />The css file to be utilized for our layout. (Utilized within the panels administration screens, AND when viewing the actual panel itself.)</li>
<li><strong>Panels:</strong><br />Defines all the various regions within your panel. This will be further utilized within our tpl.php file.</li>
</ol>

View File

@@ -0,0 +1,93 @@
This module provides by default the ability to translate panel display and
panel pane titles.
Further it introduced an extension to the ctools content_types plugin.
You can now define translatable settings which will be registered in i18n.
Out of the box the module extends the custom content content_type to allow
translation of the content.
Requirements:
Ctools 7.x-1.x-dev (Jan 28-2014 or newer)
Panels 7.x-3.x-dev (Jan 28-2014 or newer)
Plugin definition extension:
------------------------------
This example shows how the content_type custom is extended:
#### Default: ####
/**
* Plugins are described by creating a $plugin array which will be used
* by the system that includes this file.
*/
$plugin = array(
'title' => t('Custom content'),
'no title override' => TRUE,
'defaults' => array('admin_title' => '', 'title' => '', 'body' => '', 'format' => filter_fallback_format(), 'substitute' => TRUE),
'js' => array('misc/autocomplete.js', 'misc/textarea.js', 'misc/collapse.js'),
// Make sure the edit form is only used for some subtypes.
'edit form' => '',
'add form' => '',
'edit text' => t('Edit'),
'all contexts' => TRUE,
);
#### Extended Configuration: ####
/**
* Plugins are described by creating a $plugin array which will be used
* by the system that includes this file.
*/
$plugin = array(
'title' => t('Custom content'),
'no title override' => TRUE,
'defaults' => array('admin_title' => '', 'title' => '', 'body' => '', 'format' => filter_fallback_format(), 'substitute' => TRUE),
'js' => array('misc/autocomplete.js', 'misc/textarea.js', 'misc/collapse.js'),
// Make sure the edit form is only used for some subtypes.
'edit form' => '',
'add form' => '',
'edit text' => t('Edit'),
'all contexts' => TRUE,
'i18n_settings' = array(
'title',
'body' => array('format' => 'plain_text'),
'items|0|title'
),
);
The new key "i18n_settings" defines an array with the settings that are
translatable. The array contains the names of the settings, they have to be
available in the "defaults" array of the content definition. If you need to
define a format use the name of the setting as the array item key and as item
another array with the detail configuration. E.g
'i18n_settings' = array('body' => array('format' => 'plain_text'))
If i18n_settings is a string it's used as callback. The expected return is an
array equal to the one used in the fix configuration.
You can even declare nested settings as translatable, to do so use '|' as
delimiter.
E.g. 'items|0|title' is evaluated as $settings['items'][0]['title']
#### Callback: ####
/**
* Plugins are described by creating a $plugin array which will be used
* by the system that includes this file.
*/
$plugin = array(
'title' => t('Custom content'),
'no title override' => TRUE,
'defaults' => array('admin_title' => '', 'title' => '', 'body' => '', 'format' => filter_fallback_format(), 'substitute' => TRUE),
'js' => array('misc/autocomplete.js', 'misc/textarea.js', 'misc/collapse.js'),
// Make sure the edit form is only used for some subtypes.
'edit form' => '',
'add form' => '',
'edit text' => t('Edit'),
'all contexts' => TRUE,
'i18n_settings' => 'ctools_custom_content_type_i18n_settings',
);
function ctools_custom_content_type_i18n_settings($conf) {
return array(
'title',
'body' => array('format' => $conf['format']),
);
}

View File

@@ -0,0 +1,50 @@
<?php
/**
* @file
* Internationalization (i18n) hooks
*/
/**
* Implements hook_i18n_object_info().
*/
function i18n_panels_i18n_object_info() {
$info['pane_configuration'] = array(
'title' => t('Pane Configuration'),
'key' => 'uuid',
'string translation' => array(
'textgroup' => 'panels',
'type' => 'pane_configuration',
'properties' => array(
'title' => t('Pane Title'),
),
),
);
$info['display_configuration'] = array(
'title' => t('Display Configuration'),
'key' => 'uuid',
'string translation' => array(
'textgroup' => 'panels',
'type' => 'display_configuration',
'properties' => array(
'title' => t('Display Title'),
),
),
);
return $info;
}
/**
* Implements hook_i18n_string_info().
*/
function i18n_panels_i18n_string_info() {
$groups['panels'] = array(
'title' => t('Panels'),
'description' => t('Translatable panels items: display and pane configuration items. E.g. Title.'),
// This group doesn't have strings with format.
'format' => FALSE,
// This group can list all strings.
'list' => FALSE,
);
return $groups;
}

View File

@@ -0,0 +1,15 @@
name = Panels translation
description = Supports translatable panels items.
dependencies[] = i18n
dependencies[] = panels
dependencies[] = i18n_string
dependencies[] = i18n_translation
package = Multilingual - Internationalization
core = 7.x
; Information added by Drupal.org packaging script on 2016-08-20
version = "7.x-3.7"
core = "7.x"
project = "panels"
datestamp = "1471704242"

View File

@@ -0,0 +1,27 @@
<?php
/**
* @file
* Internationalization (i18n) submodule: Panels translation.
*/
/**
* Implements hook_requirements().
*/
function i18n_panels_requirements($phase) {
$requirements = array();
// Check only for status report, to allow update / install.
if ($phase == 'runtime') {
// Check if the panels module runs with uuids.
$requirements['uuid'] = array(
'title' => t('Panels uuid support.'),
'severity' => REQUIREMENT_OK,
'value' => t('Available'),
);
if (!db_field_exists('panels_pane', 'uuid')) {
$requirements['uuid']['severity'] = REQUIREMENT_ERROR;
$requirements['uuid']['value'] = t('Not found. Please apply the provided patches and run the update script.');
}
}
return $requirements;
}

View File

@@ -0,0 +1,442 @@
<?php
/**
* @file
* Internationalization (i18n) submodule: Panels translation.
*/
/**
* Fetch the i18n_settings of the content type if there are any.
*
* @param stdClass $pane
* The pane to deal with.
*
* @return array|false
* Settings or FALSE if none are present.
*/
function i18n_panels_get_i18n_settings($pane) {
ctools_include('content');
$content_type = ctools_get_content_type($pane->type);
if (isset($content_type['i18n_settings'])) {
if (is_string($content_type['i18n_settings']) && function_exists($content_type['i18n_settings'])) {
$content_type['i18n_settings'] = $content_type['i18n_settings']($pane->configuration);
}
}
// Provide the override title string as translation for all panes that have
// this setting enabled.
if (isset($pane->configuration['override_title']) && $pane->configuration['override_title']) {
if (isset($content_type['i18n_settings']) && is_array($content_type['i18n_settings'])) {
$content_type['i18n_settings'][] = 'override_title_text';
}
else {
$content_type['i18n_settings'] = array('override_title_text');
}
}
return isset($content_type['i18n_settings']) ? $content_type['i18n_settings'] : FALSE;
}
/**
* Returns the translation object of the pane.
*
* @param stdClass $pane
* The pane to deal with.
*
* @return stdClass|FALSE
* Returns FALSE if no translation is necessary.
*/
function i18n_panels_get_i18n_translation_object($pane) {
$translation_object = array();
// Handle content type specific i18n settings.
if ($i18n_settings = i18n_panels_get_i18n_settings($pane)) {
// Register translatable settings.
foreach ($i18n_settings as $i18n_setting => $settings) {
if (!is_array($settings)) {
$i18n_setting = $settings;
$settings = array('format' => 'plain_text');
}
$translation_object[$i18n_setting] = NULL;
$key_exists = FALSE;
// Ensure a nested setting is "unpacked".
$config_value = drupal_array_get_nested_value($pane->configuration, explode('|', $i18n_setting), $key_exists);
// If we reached the end of the nested setting use the value as source.
if ($key_exists) {
$translation_object[$i18n_setting] = array(
'string' => $config_value,
'format' => $settings['format'],
);
$translation_object['panels_i18n_settings'][$i18n_setting] = $settings;
}
}
}
// Check if this pane has a custom title enabled.
if (!empty($pane->configuration['override_title'])) {
$translation_object['title']['string'] = $pane->configuration['override_title_text'];
}
if (!empty($translation_object)) {
return (object) $translation_object;
}
return FALSE;
}
/**
* Implements hook_panels_pane_insert().
*
* @param stdClass $pane
* The pane to deal with.
*/
function i18n_panels_panels_pane_insert($pane) {
i18n_panels_panels_pane_update($pane);
}
/**
* Implements hook_panels_pane_update().
*
* @param stdClass $pane
* The pane to deal with.
*/
function i18n_panels_panels_pane_update($pane) {
if ($translation_object = i18n_panels_get_i18n_translation_object($pane)) {
$translation_object->uuid = $pane->uuid;
$status = i18n_string_object_update('pane_configuration', $translation_object);
}
}
/**
* Implements hook_panels_pane_delete().
*
* @param array $pids
* Array with the panel ids to delete.
*/
function i18n_panels_panels_pane_delete($pids) {
if (!empty($pids)) {
// Fetch the uuids from the db.
$uuids = db_select('panels_pane')
->fields('panels_pane', array('uuid'))
->condition('pid', $pids)
->execute()
->fetchCol();
foreach ($uuids as $uuid) {
// Create dummy pane with uuid as property.
$pane = (object) array('uuid' => $uuid);
i18n_string_object_remove('pane_configuration', $pane);
}
}
}
/**
* Implements hook_panels_pane_prerender().
*
* @param stdClass $pane
* The pane to deal with.
*/
function i18n_panels_panels_pane_prerender($pane) {
// Check if this pane has translations.
if (isset($pane->uuid) && $translation_object = i18n_panels_get_i18n_translation_object($pane)) {
$translation_object->uuid = $pane->uuid;
// Send to translation.
$translation_object = i18n_string_object_translate('pane_configuration', $translation_object);
unset($translation_object->uuid, $translation_object->i18n_settings);
foreach ($translation_object as $i18n_setting => $translated_setting) {
if ($i18n_setting != 'panels_i18n_settings') {
if (is_array($translated_setting)) {
$translated_setting = $translated_setting['string'];
}
drupal_array_set_nested_value($pane->configuration, explode('|', $i18n_setting), $translated_setting);
}
}
}
}
/**
* Implements hook_panels_display_save().
*
* @param panels_display $display
* The display to deal with.
*/
function i18n_panels_panels_display_save($display) {
$status = i18n_string_object_update('display_configuration', $display);
}
/**
* Implements hook_panels_display_delete().
*
* @param int $did
* Id of the display to delete.
*/
function i18n_panels_panels_delete_display($did) {
// Fetch uuid to delete the translations.
$uuid = db_select('panels_display')
->fields('panels_display', array('uuid'))
->condition('did', $did)
->execute()
->fetchColumn();
// Build a dummy display.
$display = (object) array('uuid' => $uuid);
// Check if this display was just saved in the db.
if (!_18n_panels_is_exported_panels_display($display)) {
// If the display was just saved in the db remove all translations.
i18n_string_object_remove('display_configuration', $display);
// Remove related pane translations too.
$pids = db_select('panels_pane')
->fields('panels_pane', array('pid'))
->condition('did', $did)
->execute()
->fetchCol();
i18n_panels_panels_pane_delete($pids);
}
else {
// If the display is exported leave the translated strings but give the user
// a hint how to clean up.
drupal_set_message(
t(
'The reverted panels display(s) were exported, please run a <a href="!link">string refresh</a> to update the translatable strings.',
array('!link' => url('admin/config/regional/translate/i18n_string'))
),
'warning',
FALSE
);
}
}
/**
* Implements hook_panels_pre_render().
*
* This function must not rely on the passed $renderer parameter. The parameter
* could be empty because this function is reused in i18n_ctools_render_alter().
* @todo Check if a drupal_alter() in panels_display::get_title() is applicable.
*
* @see i18n_ctools_render_alter()
*
* @param panels_display $display
* The display to deal with.
* @param panels_renderer_standard $renderer
* The renderer to deal with.
*/
function i18n_panels_panels_pre_render(&$display, $renderer) {
// Avoid double translations.
if (!isset($display->i18n_panels_title_translated)) {
$translation = i18n_string_object_translate('display_configuration', $display);
if (is_array($translation->title)) {
$display->title = $translation->title['string'];
}
else {
$display->title = $translation->title;
}
$display->i18n_panels_title_translated = TRUE;
}
}
/**
* Implements hook_ctools_render_alter().
*
* Under some circumstances the title of the panel page is set before
* hook_panels_pre_render() is fired. Such cases can be handled with this hook.
* @todo Check if a drupal_alter() in panels_display::get_title() is applicable.
*/
function i18n_ctools_render_alter(&$info, $page, $context) {
// @todo Find a better way to detect a panels page.
if ($page === TRUE && !empty($info['content']['#display']) && $info['content']['#display'] instanceof panels_display) {
i18n_panels_panels_pre_render($info['content']['#display'], NULL);
// Set the info title. This is used to set the page title.
$info['title'] = $info['content']['#display']->get_title();
}
}
/**
* Implements hook_ctools_plugin_post_alter().
*
* Register some translatable configuration settings for plugins.
*
*/
function i18n_panels_ctools_plugin_post_alter(&$plugin, $plugin_type_info) {
if ($plugin_type_info['type'] == 'content_types') {
// Modify custom content.
if ($plugin['name'] == 'custom') {
// Register callback to get the translatable settings.
$plugin['i18n_settings'] = 'ctools_custom_content_type_i18n_settings';
}
}
}
/**
* Callback to provide the translatable settings appropriate to the config.
*
* @param array $conf
* Content type configuration.
*
* @return array
* i18n_settings configuration.
*/
function ctools_custom_content_type_i18n_settings($conf) {
return array(
'title',
'body' => array('format' => $conf['format']),
);
}
/**
* Implements hook_i18n_string_list_TEXTGROUP_alter().
*
* Necessary to support the dynamic translatable settings defined by ctools
* content types.
*/
function i18n_panels_i18n_string_list_panels_alter(&$strings, $type = NULL, $object = NULL) {
if (isset($object->panels_i18n_settings)) {
foreach ($object->panels_i18n_settings as $i18n_setting => $settings) {
if (isset($object->{$i18n_setting})) {
$strings['panels'][$type][$object->uuid][$i18n_setting] = $object->{$i18n_setting};
}
}
}
}
/**
* Implements hook_i18n_string_list().
*
* @todo Figure out a generic solution to fetch exported displays.
*/
function i18n_panels_i18n_string_list($group) {
$strings = array();
if ($group == 'panels') {
// Fetch all available displays.
$displays = _18n_panels_fetch_all_panel_displays();
foreach ($displays as $display) {
if (empty($display->uuid)) {
drupal_set_message(t('The display %display has no uuid, please resave or re-export it.', array('%display' => $display->did)), 'warning');
continue;
}
// Avoid duplicated runs _18n_panels_fetch_all_panel_displays() probably
// returns the same display twice, one for the db based and one for the
// exported one.
if (isset($strings['panels']['display_configuration'][$display->uuid])) {
continue;
}
$strings['panels']['display_configuration'][$display->uuid]['title']['string'] = $display->title;
foreach ($display->content as $pane) {
if (empty($pane->uuid)) {
// Fetch exported uuid and validate it.
$uuid = str_replace('new-', '', $pane->pid);
if (!panels_uuid_is_valid($uuid)) {
drupal_set_message(t('The pane %pane has no uuid, please resave or re-export it.', array('%pane' => $pane->pid)), 'warning');
continue;
}
$pane->uuid = $uuid;
}
if ($translation_object = i18n_panels_get_i18n_translation_object($pane)) {
// Split up all strings and add them to the list.
$pane_strings = (array) $translation_object;
unset($pane_strings['panels_i18n_settings']);
foreach ($pane_strings as $key => $pane_string) {
$strings['panels']['pane_configuration'][$pane->uuid][$key] = $pane_string;
}
}
}
}
}
return $strings;
}
/**
* Checks if the give display is exported or only stored in the db.
*
* @return boolean
* TRUE if the display is available from code.
*/
function _18n_panels_is_exported_panels_display($display) {
if (isset($display->uuid)) {
$displays = _18n_panels_fetch_all_panel_displays();
return isset($displays['exported-' . $display->uuid]);
}
return FALSE;
}
/**
* Returns a list of really all available panel displays.
*
* The list is statically cached. Use the parameter $reset to refresh the list
* during the same request.
* Probably returns the same display twice - once with the db based and once
* the exported one.
*
* @todo I bet there are better ways to solve this mess.
*
* @param boolean $reset
* Reset the static cache.
*
* @return array
* List of all panel displays.
*/
function _18n_panels_fetch_all_panel_displays($reset = FALSE) {
$displays = &drupal_static(__FUNCTION__, array());
if (!empty($displays) && !$reset) {
return $displays;
}
// Fetch db based displays.
$dids = db_select('panels_display')->fields('panels_display', array('did'))->execute()->fetchCol();
$displays = panels_load_displays($dids);
// Fetch exported displays.
ctools_include('export');
foreach (ctools_export_crud_load_all('panels_display') as $panels_display) {
if (!empty($panels_display->uuid)) {
$displays['exported-' . $panels_display->uuid] = $panels_display;
}
}
// Fetch mini panels.
$mini_panels = ctools_export_crud_load_all('panels_mini');
foreach ($mini_panels as $pane) {
if (!empty($pane->display->uuid)) {
$displays['exported-' . $pane->display->uuid] = $pane->display;
}
}
// Fetch in page manager embedded displays.
if (module_exists('page_manager')) {
module_load_include('inc', 'page_manager', 'page_manager.admin');
$tasks = page_manager_get_tasks_by_type('page');
$pages = array('operations' => array(), 'tasks' => array());
page_manager_get_pages($tasks, $pages);
foreach ($pages['tasks'] as $task) {
$page = page_manager_cache_load($task);
$task_info = page_manager_get_task_subtasks($page->task);
foreach ($page->handler_info as $id => $info) {
$page_manager_handler = $page->handlers[$id];
if ($page_manager_handler->handler == 'panel_context') {
// @todo Is there really no better way to check this?
$is_exported = ($page_manager_handler->export_type == (EXPORT_IN_CODE | EXPORT_IN_DATABASE) || (isset($page->subtask['storage']) && $page->subtask['storage'] == t('Overridden')));
if (!empty($page_manager_handler->conf['display'])) {
$panels_display = $page_manager_handler->conf['display'];
$displays['exported-' . $panels_display->uuid] = $panels_display;
}
elseif ($is_exported && isset($page_manager_handler->conf['did'])) {
$panels_display = panels_load_display($page_manager_handler->conf['did']);
if (isset($panels_display->uuid)) {
$displays['exported-' . $panels_display->uuid] = $panels_display;
}
}
}
}
}
}
// Fetch panelizer displays.
if (module_exists('panelizer')) {
// Fetch all default handlers.
$panelizer_defaults = ctools_export_crud_load_all('panelizer_defaults');
foreach ($panelizer_defaults as $panelizer_default) {
$displays['exported-' . $panelizer_default->display->uuid] = $panelizer_default->display;
}
}
return $displays;
}

View File

@@ -9,6 +9,8 @@
* Preprocess the primary entry level theme.
*/
function template_preprocess_panels_add_content_modal(&$vars) {
$vars['categories_array'] = array();
// Process the list of categories.
foreach ($vars['categories'] as $key => $category_info) {
// 'root' category is actually displayed under the categories, so
@@ -77,7 +79,10 @@ function template_preprocess_panels_add_content_link(&$vars) {
$vars['description'] = isset($vars['content_type']['description']) ? $vars['content_type']['description'] : $vars['title'];
$vars['icon'] = ctools_content_admin_icon($vars['content_type']);
$vars['url'] = $vars['renderer']->get_url('add-pane', $vars['region'], $vars['content_type']['type_name'], $vars['content_type']['subtype_name']);
$vars['image_button'] = ctools_ajax_image_button($vars['icon'], $vars['url'], $vars['description'], 'panels-modal-add-config');
$vars['text_button'] = ctools_ajax_text_button($vars['title'], $vars['url'], $vars['description'], 'panels-modal-add-config');
$subtype_class = 'add-content-link-' . str_replace('_', '-', $vars['content_type']['subtype_name']);
$vars['image_button'] = ctools_ajax_image_button($vars['icon'], $vars['url'], $vars['description'], $subtype_class . '-image-button panels-modal-add-config');
$vars['text_button'] = ctools_ajax_text_button($vars['title'], $vars['url'], $vars['description'], $subtype_class . '-text-button panels-modal-add-config');
if (function_exists('ctools_ajax_icon_text_button')) {
$vars['icon_text_button'] = ctools_ajax_icon_text_button($vars['title'], $vars['icon'], $vars['url'], $vars['description'], $subtype_class . '-icon-text-button panels-modal-add-config');
}
}

View File

@@ -89,7 +89,7 @@ class panels_allowed_layouts {
* as allowed or not allowed on the initial call to panels_allowed_layouts::set_allowed()
*
*/
function panels_allowed_layouts($start_allowed = TRUE) {
function __construct($start_allowed = TRUE) {
// TODO would be nice if there was a way to just fetch the names easily
foreach ($this->list_layouts() as $layout_name) {
$this->allowed_layout_settings[$layout_name] = $start_allowed ? 1 : 0;
@@ -352,11 +352,21 @@ function panels_common_settings_submit($form, &$form_state) {
$module_name = $form_state['values']['module_name'];
variable_set($module_name . '_default', $form_state['values']['panels_common_default']);
if (!$form_state['skip']) {
// merge the broken apart array neatly back together
$allowed = $form_state['values']['allowed'];
// Merge the broken apart array neatly back together.
$allowed_content_types = array();
foreach ($form_state['values']['allowed'] as $allowed) {
$allowed_content_types = array_merge($allowed_content_types, $form_state['values']['content_types'][$allowed]['options']);
$values = $form_state['values']['content_types'][$allowed]['options'];
// If new content of the type is not added, storing a lisy of disabled
// content is not needed.
if (!$form_state['values']['panels_common_default'][$allowed]) {
$values = array_filter($values);
}
$allowed_content_types = array_merge($allowed_content_types, $values);
}
// Values from checkboxes are the same string as they key, but we only need
// to store the boolean value.
foreach ($allowed_content_types as &$value) {
$value = (bool) $value;
}
variable_set($module_name . '_allowed_types', $allowed_content_types);
}

View File

@@ -240,7 +240,7 @@ function panels_edit_display_settings_form($form, &$form_state) {
'#type' => 'textfield',
'#default_value' => $display->title,
'#title' => t('Title'),
'#description' => t('The title of this panel. If left blank, a default title may be used. Set to No Title if you want the title to actually be blank.'),
'#description' => t('The title of this panel. If left blank, a default title may be used. If you want the title actually to be blank, change the "Title type" dropdown from "Manually Set" to "No Title".'),
'#process' => array('ctools_dependent_process'),
'#dependency' => array('edit-display-title-hide-title' => array(PANELS_TITLE_FIXED)),
'#maxlength' => 255,

View File

@@ -94,6 +94,7 @@ function panels_choose_layout($form, &$form_state) {
}
}
ctools_add_js('panels-base', 'panels');
ctools_add_js('layout', 'panels');
$form['categories'] = array(
@@ -320,6 +321,8 @@ function panels_change_layout_submit($form, &$form_state) {
$display->panels = $content;
$display->layout = $form_state['layout'];
panels_edit_display_settings_form_submit($form, $form_state);
}
/**

View File

@@ -125,7 +125,7 @@ class panels_cache_object {
/**
* When constructed, take a snapshot of our existing out of band data.
*/
function panels_cache_object() {
function __construct() {
$this->head = drupal_add_html_head();
$this->css = drupal_add_css();
$this->tokens = ctools_set_page_token();
@@ -173,15 +173,36 @@ class panels_cache_object {
$start = $this->js;
$this->js = array();
// Use the advanced mapping function from Drupal >= 7.23 if available.
$array_mapping_func = function_exists('drupal_array_diff_assoc_recursive') ? 'drupal_array_diff_assoc_recursive' : 'array_diff_assoc';
// If there are any differences between the old and the new javascript then
// store them to be added later.
if ($diff = array_diff_assoc($js, $start)) {
$this->js = $diff;
}
// Special case the settings key and get the difference of the data.
if ($settings_diff = array_diff_assoc($js['settings']['data'], $start['settings']['data'])) {
$this->js['settings'] = $settings_diff;
if ($diff = $array_mapping_func($js, $start)) {
// Iterate over the diff to ensure we keep the keys on merge and don't add
// unnecessary items.
foreach ($diff as $key => $diff_data) {
// Special case the settings key and get the difference of the data.
if ($key === 'settings') {
// Iterate over the diff to ensure we keep the keys on merge and don't
// add unnecessary items.
if (isset($diff[$key]['data'])) {
foreach ($diff[$key]['data'] as $settings_key => $settings_data) {
// Merge the changes with the base to get a complete settings
// array.
$this->js[$key]['data'][] = drupal_array_merge_deep($settings_data, $diff[$key]['data'][$settings_key]);
}
}
}
else {
$this->js[$key] = $diff_data;
// Check if the key was present already and if so merge the changes
// with the original data to get the full settings array.
if (isset($start[$key])) {
$this->js[$key] = drupal_array_merge_deep($start[$key], $this->js[$key]);
}
}
}
}
// And for tokens:
@@ -213,7 +234,7 @@ class panels_cache_object {
drupal_add_js($args['data'], $args);
}
else {
foreach ($args as $setting) {
foreach ($args['data'] as $setting) {
drupal_add_js($setting, 'setting');
}
}
@@ -457,6 +478,31 @@ function panels_get_renderer_pipelines($sort = TRUE) {
return $pipelines;
}
/**
* Fetch metadata on a specific panels_storage plugin.
*
* @param $storage
* Name of a panel_storage plugin.
*
* @return
* An array with information about the requested panels_storage plugin
*/
function panels_get_panels_storage_plugin($storage) {
ctools_include('plugins');
return ctools_get_plugins('panels', 'panels_storage', $storage);
}
/**
* Fetch metadata for all panels_storage plugins.
*
* @return
* An array of arrays with information about all available panels_storage plugins.
*/
function panels_get_panels_storage_plugins() {
ctools_include('plugins');
return ctools_get_plugins('panels', 'panels_storage');
}
/**
* Get a function from a plugin, if it exists.
*

View File

@@ -80,7 +80,7 @@ Drupal.Panels.Draggable = {
regionId: 'panel-region-',
// What to add to the front of a the id to get the form id for a panel
formId: 'input#edit-',
formId: '#edit-',
maxWidth: 250,
@@ -492,8 +492,8 @@ Drupal.behaviors.PanelsDisplayEditor = {
Drupal.Panels.Draggable.savePositions();
// Bind buttons.
$('input#panels-hide-all', context).click(Drupal.Panels.clickHideAll);
$('input#panels-show-all', context).click(Drupal.Panels.clickShowAll);
$('#panels-hide-all', context).click(Drupal.Panels.clickHideAll);
$('#panels-show-all', context).click(Drupal.Panels.clickShowAll);
Drupal.Panels.bindClickDelete(context);
@@ -513,6 +513,11 @@ Drupal.behaviors.PanelsDisplayEditor = {
$('#panels-preview').html(html);
});
// Bind modal detach behaviors to cancel current form.
$(document).bind('CToolsDetachBehaviors', function(event, context) {
$('#edit-cancel-style', context).trigger('click');
});
var setTitleClass = function () {
if ($('#edit-display-title-hide-title').val() == 2) {
$('#panels-dnd-main').removeClass('panels-set-title-hide');

View File

@@ -13,6 +13,45 @@
}
};
Drupal.Panels.AddContentModalQuickFilter = function() {
var input_field = $('.panels-add-content-modal input[name=quickfilter]');
input_field.data.panelsAddContentModalQuickFilter = {
keyupTimeout: false,
filter: function(e) {
if (this.val().length) {
var search_expression = this.val().toLowerCase();
$('.panels-add-content-modal .panels-section-columns .content-type-button').each(function(i, elem) {
if ($(elem).text().toLowerCase().search(search_expression) > -1) {
$(elem).show();
}
else {
$(elem).hide();
}
});
}
else {
$('.panels-add-content-modal .panels-section-columns .content-type-button').show();
}
}
}
// Use timeout to reduce the iteration over the DOM tree.
input_field.bind('keyup.AddContentModalQuickFilter', jQuery.proxy(function(e){
var filter = $(this).data.panelsAddContentModalQuickFilter;
if (filter.keyupTimeout) {
window.clearTimeout(filter.timeout);
filter.keyupTimeout = false;
}
// If there's only one item left and enter is hit select it right away.
if (e.keyCode == 13 && $('.panels-add-content-modal .panels-section-columns .content-type-button:visible').length == 1) {
$('.panels-add-content-modal .panels-section-columns .content-type-button:visible a').trigger('click');
}
else {
filter.keyupTimeout = window.setTimeout(jQuery.proxy(filter.filter, this), 200);
}
}, input_field));
input_field.focus();
};
Drupal.Panels.restripeTable = function(table) {
// :even and :odd are reversed because jquery counts from 0 and
// we count from 1, so we're out of sync.

View File

@@ -1,28 +0,0 @@
(function ($) {
Drupal.Panels = Drupal.Panels || {};
Drupal.Panels.autoAttach = function() {
if ($.browser.msie) {
// If IE, attach a hover event so we can see our admin links.
$("div.panel-pane").hover(
function() {
$('div.panel-hide', this).addClass("panel-hide-hover"); return true;
},
function() {
$('div.panel-hide', this).removeClass("panel-hide-hover"); return true;
}
);
$("div.admin-links").hover(
function() {
$(this).addClass("admin-links-hover"); return true;
},
function(){
$(this).removeClass("admin-links-hover"); return true;
}
);
}
};
$(Drupal.Panels.autoAttach);
})(jQuery);

View File

@@ -0,0 +1,264 @@
<?php
/**
* @file
* Hooks provided by Panels.
*/
/**
* Allow modules to provide their own caching mechanism for the display editor.
*
* @param string $argument
* The second half of the cache key. Full key module:TASK_NAME:HANDLER_NAME
* passed part: TASK_NAME:HANDLER_NAME
* @param stdClass $cache
* The display to cache.
*/
function hook_panels_cache_set($argument, $cache) {
list($handler, $item) = _panels_mini_panels_cache_get($argument);
$item->mini_panels_display_cache = $cache;
$handler->edit_cache_set_key($item, $argument);
}
/**
* Allow modules to provide their own caching mechanism for the display editor.
*
* @param string $argument
* The second half of the cache key. Full key module:TASK_NAME:HANDLER_NAME
* passed part: TASK_NAME:HANDLER_NAME
*
* @return stdClass|NULL
* The cached display or NULL if the cache wasn't hit.
*/
function hook_panels_cache_get($argument) {
ctools_include('common', 'panels');
list($handler, $item) = _panels_mini_panels_cache_get($argument);
if (isset($item->mini_panels_display_cache)) {
return $item->mini_panels_display_cache;
}
$cache = new stdClass();
$cache->display = $item->display;
$cache->display->context = ctools_context_load_contexts($item);
$cache->display->cache_key = 'panels_mini:' . $argument;
$cache->content_types = panels_common_get_allowed_types('panels_mini', $cache->display->context);
$cache->display_title = TRUE;
// @TODO support locking.
$cache->locked = FALSE;
return $cache;
}
/**
* Allow modules to provide their own caching mechanism for the display editor.
*
* @param string $argument
* The second half of the cache key. Full key module:TASK_NAME:HANDLER_NAME
* passed part: TASK_NAME:HANDLER_NAME
* @param stdClass $cache
* The display to cache.
*
* @return stdClass
* The cached display.
*/
function hook_panels_cache_save($argument, $cache) {
list($handler, $item) = _panels_mini_panels_cache_get($argument);
$item->display = $cache->display;
panels_mini_save($item);
$handler->edit_cache_clear($item);
return $item;
}
/**
* Allow modules to provide their own caching mechanism for the display editor.
*
* @param string $argument
* The second half of the cache key. Full key module:TASK_NAME:HANDLER_NAME
* passed part: TASK_NAME:HANDLER_NAME
* @param stdClass $cache
* The cached display.
*/
function hook_panels_cache_clear($argument, $cache) {
list($handler, $item) = _panels_mini_panels_cache_get($argument);
$handler->edit_cache_clear($item);
}
/**
* Allow modules to adjust the rendering array of the panels dashboard.
*
* @param array $vars
* The output variables.
*/
function hook_panels_dashboard_blocks(&$vars) {
$vars['links']['panels_node'] = array(
'title' => l(t('Panel node'), 'node/add/panel'),
'description' => t('Panel nodes are node content and appear in your searches, but are more limited than panel pages.'),
'weight' => -1,
);
}
/**
* Allow to alter the pane content to render.
*
* This happens after the keyword substitution.
*
* @param stdClass $content
* The content block to render.
* @param stdClass $pane
* The pane object.
* @param array $args
* The display arguments.
* @param array $contexts
* Array with the used contexts.
*/
function hook_panels_pane_content_alter($content, $pane, $args, $contexts) {
// Don't display titles.
unset($content->title);
}
/**
* Allow modules to provide a mechanism to break locks.
*
* @param string $argument
* The second half of the cache key. Full key module:TASK_NAME:HANDLER_NAME
* passed part: TASK_NAME:HANDLER_NAME
* @param stdClass $cache
* The cached display.
*/
function hook_panels_edit_cache_break_lock($argument, $cache) {
$cache->locked = FALSE;
}
/**
* Fired before a panels display is rendered.
*
* Last chance to modify the panels display or add output before the keyword
* substitution runs and the panels display is rendered.
*
* @param panels_display $panels_display
* The panels display that will be rendered.
* @param stdClass $renderer
* The renderer object that will be used to render.
*
* @return string
* Additional output to add before the panels display.
*/
function hook_panels_pre_render($panels_display, $renderer) {
$translation = i18n_string_object_translate('panels_display_configuration', $panels_display);
$panels_display->title = $translation->title;
}
/**
* Fired after a panels display is rendered.
*
* Allow to add additional output after the output of the panels display.
*
* @param panels_display $panels_display
* The rendered panels display.
* @param stdClass $renderer
* The used renderer object.
*
* @return string
* Additional output to add after the panels display.
*/
function hook_panels_post_render($panels_display, $renderer) {
return t('Output proudly sponsored by panels.');
}
/**
* Fired before a new pane is inserted in the storage.
*
* @param stdClass $pane
* Pane that will be rendered.
*/
function hook_panels_pane_insert($pane) {
// Check if this pane has a custom title enabled.
if (!empty($pane->configuration['override_title'])) {
$translation_object = (object) array(
'pid' => $pane->pid,
'title' => $pane->configuration['override_title_text'],
);
$status = i18n_string_object_update('panels_pane_configuration', $translation_object);
}
}
/**
* Fired before a changed pane is updated in the storage.
*
* @param stdClass $pane
* Pane that will be rendered.
*/
function hook_panels_pane_update($pane) {
// Check if this pane has a custom title enabled.
if (!empty($pane->configuration['override_title'])) {
$translation_object = (object) array(
'pid' => $pane->pid,
'title' => $pane->configuration['override_title_text'],
);
$status = i18n_string_object_update('panels_pane_configuration', $translation_object);
}
}
/**
* Fired before a panel is rendered.
*
* Last chance to modify the pane before the keyword substitution runs and the
* pane is rendered.
*
* @param stdClass $pane
* Pane that will be rendered.
*/
function hook_panels_pane_prerender($pane) {
// Check if this pane has a custom title enabled.
if (!empty($pane->configuration['override_title'])) {
$translation_object = (object) array(
'pid' => $pane->pid,
'title' => $pane->configuration['override_title_text'],
);
$translation_object = i18n_string_object_translate('panels_pane_configuration', $translation_object);
$pane->configuration['override_title_text'] = $translation_object->title;
}
}
/**
* Fired before panes are deleted.
*
* @param array $pids
* Array with the panel id's to delete.
*/
function hook_panels_pane_delete($pids) {
foreach ($pids as $pid) {
// Create dummy pane with pid as property.
$pane = (object) array('pid' => $pid);
i18n_string_object_remove('panels_pane_configuration', $pane);
}
}
/**
* Fired after a display is saved.
*
* @param panels_display $display
* The display to save.
*/
function hook_panels_display_save($display) {
i18n_string_object_update('display_configuration', $display);
}
/**
* Fired before a display is deleted.
*
* @param integer $did
* Id of the display to delete.
*/
function hook_panels_delete_display($did) {
$uuid = db_select('panels_display')
->fields('panels_display', array('uuid'))
->condition('did', $did)
->execute()
->fetchColumn();
$display = (object) array('uuid' => $uuid);
i18n_string_object_remove('display_configuration', $display);
}

View File

@@ -10,9 +10,9 @@ files[] = includes/legacy.inc
files[] = includes/plugins.inc
files[] = plugins/views/panels_views_plugin_row_fields.inc
; Information added by drupal.org packaging script on 2013-03-02
version = "7.x-3.3+39-dev"
; Information added by Drupal.org packaging script on 2016-08-20
version = "7.x-3.7"
core = "7.x"
project = "panels"
datestamp = "1362187383"
datestamp = "1471704242"

View File

@@ -17,7 +17,7 @@ function panels_requirements_install() {
// Assume that if the user is running an installation profile that both
// Panels and CTools are the same release.
if (!(defined('MAINTENANCE_MODE') && MAINTENANCE_MODE == 'install')) {
// apparently the install process doesn't include .module files,
// Apparently the install process doesn't include .module files,
// so we need to force the issue in order for our versioning
// check to work.
if (!defined('PANELS_REQUIRED_CTOOLS_API')) {
@@ -30,24 +30,81 @@ function panels_requirements_install() {
include_once drupal_get_path('module', 'ctools') . '/ctools.module';
}
if (!module_invoke('ctools', 'api_version', PANELS_REQUIRED_CTOOLS_API)) {
$requirements['panels_ctools'] = array(
'title' => $t('CTools API Version'),
'value' => CTOOLS_API_VERSION,
'severity' => REQUIREMENT_ERROR,
'description' => t('The CTools API version is too old for Panels. Panels needs at least %version.', array('%version' => PANELS_REQUIRED_CTOOLS_API))
);
$requirements['panels_ctools'] = array(
'title' => $t('CTools API Version'),
'value' => CTOOLS_API_VERSION,
'severity' => REQUIREMENT_ERROR,
'description' => t('The CTools API version is too old for Panels. Panels needs at least %version.', array('%version' => PANELS_REQUIRED_CTOOLS_API)),
);
}
}
return $requirements;
}
/**
* Implementation of hook_schema().
* Implements of hook_schema().
*/
function panels_schema() {
// This should always point to our 'current' schema. This makes it relatively easy
// to keep a record of schema as we make changes to it.
return panels_schema_4();
// This should always point to our 'current' schema. This makes it relatively
// easy to keep a record of schema as we make changes to it.
return panels_schema_8();
}
function panels_schema_8() {
$schema = panels_schema_7();
// Add the storage type and id columns.
$schema['panels_display']['fields']['storage_type'] = array(
'type' => 'varchar',
'length' => 255,
'default' => '',
);
$schema['panels_display']['fields']['storage_id'] = array(
'type' => 'varchar',
'length' => 255,
'default' => '',
);
return $schema;
}
function panels_schema_7() {
$schema = panels_schema_6();
// Update field lengths to 255 chars.
$schema['panels_pane']['fields']['subtype']['length'] = '255';
$schema['panels_pane']['fields']['panel']['length'] = '255';
$schema['panels_pane']['fields']['type']['length'] = '255';
return $schema;
}
function panels_schema_6() {
$schema = panels_schema_5();
$schema['cache_panels'] = drupal_get_schema_unprocessed('system', 'cache');
return $schema;
}
function panels_schema_5() {
$schema = panels_schema_4();
$schema['panels_display']['fields']['uuid'] = array(
'type' => 'char',
'length' => '36',
);
$schema['panels_display']['export']['key'] = 'uuid';
$schema['panels_display']['export']['key name'] = 'UUID';
$schema['panels_pane']['fields']['uuid'] = array(
'type' => 'char',
'length' => '36',
);
$schema['panels_pane']['export']['key'] = 'uuid';
$schema['panels_pane']['export']['key name'] = 'UUID';
return $schema;
}
function panels_schema_4() {
@@ -375,3 +432,178 @@ function panels_update_7301() {
return t('panels_pane.lock field already existed, update skipped.');
}
/**
* Adding universally unique identifiers to panels.
*
* Note: This update hook is not written well. It calls apis which uses the
* most updated drupal database, causing missing columns or tables errors. To
* mitigate the issue, we've added updates from 7303 and 7305. Future updates
* should go below the 7305 update.
*
* See https://www.drupal.org/node/2787123 for more info.
*/
function panels_update_7302() {
if (!module_load_include('inc', 'ctools', 'includes/uuid')) {
throw new DrupalUpdateException(t('Ctools UUID support not detected. You must update to a more recent version of the ctools module.'));
}
// Run the 7303 update first to avoid caching issues.
// This *probably* should be placed right above update 7305, however it was
// tested here and re-testing this update is difficult, so it stays here.
panels_update_7303();
// Load the schema.
$schema = panels_schema_5();
$msg = array();
// Add the uuid column to the pane table.
$table = 'panels_pane';
$field = 'uuid';
// Due to a previous failure, the column may already exist:
if (!db_field_exists($table, $field)) {
$spec = $schema[$table]['fields'][$field];
db_add_field($table, $field, $spec);
$msg[] = t('Added panels_pane.uuid column.');
}
// Add the uuid column to the display table.
$table = 'panels_display';
$field = 'uuid';
// Due to a previous failure, the column may already exist:
if (!db_field_exists($table, $field)) {
$spec = $schema[$table]['fields'][$field];
db_add_field($table, $field, $spec);
$msg[] = t('Added panels_display.uuid column.');
}
if (empty($msg)) {
$msg[] = t('UUID column already present in the panels_display & panels_pane tables.');
}
// Update all DB-based panes & displays to ensure that they all contain a UUID.
$display_dids = db_select('panels_display')
->fields('panels_display', array('did'))
->condition(db_or()
->condition('uuid', '')
->isNull('uuid')
)
->execute()
->fetchCol();
// Check the panes as well, for paranoia.
$pane_dids = db_select('panels_pane')
->distinct()
->fields('panels_pane', array('did'))
->condition(db_or()
->condition('uuid', '')
->isNull('uuid')
)
->execute()
->fetchCol();
$dids = array_unique(array_merge($display_dids, $pane_dids));
// Before using panels_save_display(), we have to make sure any new fields
// are added from future updates.
panels_update_7305();
// If the Panels module is disabled we don't have access to
// panels_load_displays().
if (!function_exists('panels_load_displays')) {
module_load_include('module', 'panels');
}
if ($displays = panels_load_displays($dids)) {
foreach ($displays as $display) {
// A display save also triggers pane saves.
panels_save_display($display);
}
$msg[] = t('Generated UUIDs for database-based panel displays and panes.');
}
else {
$msg[] = t('No database-based panel displays or panes for which to generate UUIDs.');
}
return implode("\n", $msg);
}
/**
* Add a custom cache table for Panels.
*/
function panels_update_7303() {
$schema = panels_schema_6();
$table_name = 'cache_panels';
if (!db_table_exists($table_name)) {
db_create_table($table_name, $schema[$table_name]);
}
}
/**
* Update "panels_pane" table field lengths to 255 chars.
*/
function panels_update_7304() {
$schema = panels_schema_7();
$update_fields = array(
'panels_pane' => array('subtype', 'panel', 'type'),
);
foreach($update_fields as $table => $fields) {
foreach($fields as $field_name) {
db_change_field($table, $field_name, $field_name, $schema[$table]['fields'][$field_name]);
}
}
}
/**
* Add the "storage_type" and "storage_id" columns to "panels_display".
*/
function panels_update_7305() {
$schema = panels_schema_8();
$new_fields = array(
'panels_display' => array('storage_type', 'storage_id'),
);
foreach ($new_fields as $table => $fields) {
foreach ($fields as $field_name) {
// Due to a previous failure, the column may already exist:
if (!db_field_exists($table, $field_name)) {
db_add_field($table, $field_name, $schema[$table]['fields'][$field_name]);
}
}
}
}
/**
* Set the storage type and id on existing page manager panels displays.
*/
function panels_update_7306() {
if (!db_table_exists('page_manager_handlers')) {
return t('Skipping update - page_manager is not installed.');
}
// Get all page_manager_handlers that have a panels context.
$result = db_query("SELECT pm.name, pm.conf FROM {page_manager_handlers} pm WHERE pm.handler = 'panel_context'");
$page_manager_panels = array();
foreach ($result as $row) {
$conf = unserialize($row->conf);
if (isset($conf['did'])) {
$page_manager_panels[$conf['did']] = $row->name;
}
}
if (!empty($page_manager_panels)) {
// Check panels displays that only have empty storage types
$result = db_query("SELECT pd.did FROM {panels_display} pd WHERE pd.did IN (:dids) AND storage_type = ''", array(':dids' => array_keys($page_manager_panels)));
foreach ($result as $row) {
db_update('panels_display')
->fields(array(
'storage_type' => 'page_manager',
'storage_id' => $page_manager_panels[$row->did],
))
->condition('did', $row->did)
->execute();
}
}
}

View File

@@ -6,7 +6,22 @@
* Core functionality for the Panels engine.
*/
define('PANELS_REQUIRED_CTOOLS_API', '2.0-alpha');
define('PANELS_REQUIRED_CTOOLS_API', '2.0.8');
/**
* The current working panels version.
*
* In a release, it should be 7.x-3.x, which should match what drush make will
* create. In a dev format, it should be 7.x-3.(x+1)-dev, which will allow
* modules depending on new features in panels to depend on panels > 7.x-3.x.
*
* To define a specific version of Panels as a dependency for another module,
* simply include a dependency line in that module's info file, e.g.:
* ; Requires Panels v7.x-3.4 or newer.
* dependencies[] = panels (>=3.4)
*/
define('PANELS_VERSION', '7.x-3.6');
define('PANELS_TITLE_FIXED', 0); // Hide title use to be true/false. So false remains old behavior.
define('PANELS_TITLE_NONE', 1); // And true meant no title.
@@ -43,7 +58,7 @@ function panels_theme() {
'variables' => array('id' => NULL, 'image' => NULL, 'title' => NULL),
);
$theme['panels_pane'] = array(
'variables' => array('output' => array(), 'pane' => array(), 'display' => array()),
'variables' => array('content' => array(), 'pane' => array(), 'display' => array()),
'path' => drupal_get_path('module', 'panels') . '/templates',
'template' => 'panels-pane',
);
@@ -258,7 +273,6 @@ function panels_init() {
}
ctools_add_css('panels', 'panels');
ctools_add_js('panels', 'panels');
}
/**
@@ -270,7 +284,7 @@ function panels_permission() {
return array(
'use panels dashboard' => array(
'title' => t("Use Panels Dashboard"),
'description' => t("Allows a user to access the !link.", array('!link' => l('Panels Dashboard', 'admin/structure/panels'))),
'description' => t('Allows a user to access the <a href="@url">Panels Dashboard</a>.', array('@url' => url('admin/structure/panels'))),
),
'view pane admin links' => array( // @todo
'title' => t("View administrative links on Panel panes"),
@@ -288,6 +302,11 @@ function panels_permission() {
'title' => t("Change layouts with the Panels In-Place Editor"),
'description' => t("Allows a user to change layouts with the IPE."),
),
'bypass access in place editing' => array(
'title' => t("Bypass access checks when using Panels In-Place Editor"),
'description' => t("Allows using IPE even if user does not have additional permissions granted by other modules."),
'restrict access' => TRUE,
),
'administer advanced pane settings' => array(
'title' => t("Configure advanced settings on Panel panes"),
'description' => t(""),
@@ -316,15 +335,13 @@ function panels_permission() {
}
/**
* Implementation of hook_flush_caches().
*
* We implement this so that we can be sure our legacy rendering state setting
* in $conf is updated whenever caches are cleared.
* Implements hook_flush_caches().
*/
//function panels_flush_caches() {
// $legacy = panels_get_legacy_state();
// $legacy->determineStatus();
//}
function panels_flush_caches() {
if (db_table_exists('cache_panels')) {
return array('cache_panels');
}
}
// ---------------------------------------------------------------------------
// CTools hook implementations
@@ -381,6 +398,7 @@ function panels_ctools_plugin_type() {
'display_renderers' => array(
'classes' => array('renderer'),
),
'panels_storage' => array(),
);
}
@@ -635,7 +653,6 @@ function panels_edit_layout($display, $finish, $destination = NULL, $allowed_lay
/**
* Forms the basis of a panel display
*
*/
class panels_display {
var $args = array();
@@ -656,8 +673,10 @@ class panels_display {
$pane->panel = $location;
}
// Get a temporary pid for this pane.
$pane->pid = "new-" . $this->next_new_pid();
// Generate a permanent uuid for this pane, and use
// it as a temporary pid.
$pane->uuid = ctools_uuid_generate();
$pane->pid = 'new-' . $pane->uuid;
// Add the pane to the approprate spots.
$this->content[$pane->pid] = &$pane;
@@ -671,23 +690,10 @@ class panels_display {
function clone_pane($pid) {
$pane = clone $this->content[$pid];
$pane->uuid = ctools_uuid_generate();
return $pane;
}
function next_new_pid() {
// We don't use static vars to record the next new pid because
// temporary pids can last for years in exports and in caching
// during editing.
$id = array(0);
foreach (array_keys($this->content) as $pid) {
if (!is_numeric($pid)) {
$id[] = substr($pid, 4);
}
}
$next_id = max($id);
return ++$next_id;
}
/**
* Get the title from a display.
*
@@ -758,6 +764,55 @@ class panels_display {
}
return $output;
}
/**
* Determine if the given user can perform the requested operation.
*
* @param string $op
* An operation like: create, read, update, or delete.
* @param object $account
* (optional) The account to check access for.
*
* @return bool
* TRUE if access is granted; otherwise FALSE.
*/
function access($op, $account = NULL) {
global $user;
if (!$account) {
$account = $user;
}
// Even administrators need to go through the access system. However, to
// support legacy plugins, user 1 gets full access no matter what.
if ($account->uid == 1) {
return TRUE;
}
if (!in_array($op, array('create', 'read', 'update', 'delete', 'change layout'))) {
return FALSE;
}
if (empty($this->storage_type) || empty($this->storage_id)) {
return FALSE;
}
if ($this->storage_type == 'unknown') {
return FALSE;
}
$storage_plugin = panels_get_panels_storage_plugin($this->storage_type);
if (!$storage_plugin) {
return FALSE;
}
$access_callback = panels_plugin_get_function('panels_storage', $storage_plugin, 'access callback');
if (!$access_callback) {
return FALSE;
}
return $access_callback($this->storage_type, $this->storage_id, $op, $account);
}
}
/**
@@ -791,6 +846,7 @@ function panels_new_pane($type, $subtype, $set_defaults = FALSE) {
$content_subtype = ctools_content_get_subtype($content_type, $subtype);
$pane->configuration = ctools_content_get_defaults($content_type, $content_subtype);
}
drupal_alter('panels_new_pane', $pane);
return $pane;
}
@@ -871,10 +927,13 @@ function panels_load_display($did) {
*
* @ingroup mainapi
*
* Note a new $display only receives a real did once it is run through this function.
* Until then, it uses a string placeholder, 'new', in place of a real did. The same
* applies to all new panes (whether on a new $display or not); in addition,
* panes have sequential numbers appended, of the form 'new-1', 'new-2', etc.
* Note that a new $display only receives a real did once it is run through
* this function, and likewise for the pid of any new pane.
*
* Until then, a new display uses a string placeholder, 'new', in place of
* a real did, and a new pane (whether on a new $display or not) appends a
* universally-unique identifier (which is stored permanently in the 'uuid'
* field). This format is also used in place of the real pid for exports.
*
* @param object $display instanceof panels_display \n
* The display object to be saved. Passed by reference so the caller need not use
@@ -884,6 +943,9 @@ function panels_load_display($did) {
*/
function panels_save_display(&$display) {
$update = (isset($display->did) && is_numeric($display->did)) ? array('did') : array();
if (empty($display->uuid) || !ctools_uuid_is_valid($display->uuid)) {
$display->uuid = ctools_uuid_generate();
}
drupal_write_record('panels_display', $display, $update);
$pids = array();
@@ -914,11 +976,26 @@ function panels_save_display(&$display) {
$pane->did = $display->did;
$old_pid = $pane->pid;
if (empty($pane->uuid) || !ctools_uuid_is_valid($pane->uuid)) {
$pane->uuid = ctools_uuid_generate();
}
drupal_write_record('panels_pane', $pane, is_numeric($pid) ? array('pid') : array());
// Allow other modules to take action after a pane is saved.
if ($pane->pid == $old_pid) {
module_invoke_all('panels_pane_update', $pane);
}
else {
module_invoke_all('panels_pane_insert', $pane);
}
if ($pane->pid != $old_pid) {
// and put it back so our pids and positions can be used
unset($display->content[$id]);
// Remove the old new-* entry from the displays content.
unset($display->content[$pid]);
// and put it back so our pids and positions can be used.
$display->content[$pane->pid] = $pane;
// If the title pane was one of our panes that just got its ID changed,
@@ -949,6 +1026,8 @@ function panels_save_display(&$display) {
$display->panels[$id] = $new_panes;
}
if (!empty($pids)) {
// Allow other modules to take action before a panes are deleted.
module_invoke_all('panels_pane_delete', $pids);
db_delete('panels_pane')->condition('pid', $pids)->execute();
}
@@ -982,6 +1061,7 @@ function panels_delete_display($display) {
else {
$did = $display;
}
module_invoke_all('panels_delete_display', $did);
db_delete('panels_display')->condition('did', $did)->execute();
db_delete('panels_pane')->condition('did', $did)->execute();
}
@@ -991,9 +1071,11 @@ function panels_delete_display($display) {
*
* This function is primarily intended as a mechanism for cloning displays.
* It generates an exact replica (in code) of the provided $display, with
* the exception that it replaces all ids (dids and pids) with 'new-*' values.
* Only once panels_save_display() is called on the code version of $display will
* the exported display written to the database and permanently saved.
* the exception that it replaces all ids (dids and pids) with place-holder
* values (consisting of the display or pane's uuid, with a 'new-' prefix).
*
* Only once panels_save_display() is called on the code version of $display
* will the exported display be written to the database and permanently saved.
*
* @see panels_page_export() or _panels_page_fetch_display() for sample implementations.
*
@@ -1015,10 +1097,12 @@ function panels_delete_display($display) {
*/
function panels_export_display($display, $prefix = '') {
ctools_include('export');
if (empty($display->uuid) || !ctools_uuid_is_valid($display->uuid)) {
$display->uuid = ctools_uuid_generate();
}
$display->did = 'new-' . $display->uuid;
$output = ctools_export_object('panels_display', $display, $prefix);
$pid_counter = &drupal_static(__FUNCTION__, 0);
// Initialize empty properties.
$output .= $prefix . '$display->content = array()' . ";\n";
$output .= $prefix . '$display->panels = array()' . ";\n";
@@ -1028,17 +1112,22 @@ function panels_export_display($display, $prefix = '') {
if (!empty($display->content)) {
$region_counters = array();
foreach ($display->content as $pane) {
$pid = 'new-' . ++$pid_counter;
if (!isset($pane->uuid) || !ctools_uuid_is_valid($pane->uuid)) {
$pane->uuid = ctools_uuid_generate();
}
$pid = 'new-' . $pane->uuid;
if ($pane->pid == $display->title_pane) {
$title_pid = $pid;
}
$pane->pid = $pid;
$output .= ctools_export_object('panels_pane', $pane, $prefix . ' ');
$output .= "$prefix " . '$display->content[\'' . $pane->pid . '\'] = $pane' . ";\n";
$output .= ctools_export_object('panels_pane', $pane, $prefix);
$output .= $prefix . '$display->content[\'' . $pane->pid . '\'] = $pane' . ";\n";
if (!isset($region_counters[$pane->panel])) {
$region_counters[$pane->panel] = 0;
}
$output .= "$prefix " . '$display->panels[\'' . $pane->panel . '\'][' . $region_counters[$pane->panel]++ .'] = \'' . $pane->pid . "';\n";
$output .= $prefix . '$display->panels[\'' . $pane->panel . '\'][' . $region_counters[$pane->panel]++ .'] = \'' . $pane->pid . "';\n";
}
}
$output .= $prefix . '$display->hide_title = ';
@@ -1288,6 +1377,7 @@ function template_preprocess_panels_pane(&$vars) {
$vars['pane_suffix'] = !empty($content->pane_suffix) ? $content->pane_suffix : '';
$vars['title'] = !empty($content->title) ? $content->title : '';
$vars['title_heading'] = !empty($content->title_heading) ? $content->title_heading : variable_get('override_title_heading', 'h2');
$vars['title_attributes_array']['class'][] = 'pane-title';
$vars['feeds'] = !empty($content->feeds) ? implode(' ', $content->feeds) : '';
@@ -1363,6 +1453,11 @@ function panels_ajax_router() {
ctools_include('cleanstring');
$renderer->clean_key = ctools_cleanstring($cache_key);
$op = $renderer->get_panels_storage_op_for_ajax($method);
if (!$cache->display->access($op)) {
return MENU_ACCESS_DENIED;
}
$output = call_user_func_array(array($renderer, $method), $args);
if (empty($output) && !empty($renderer->commands)) {
@@ -1674,6 +1769,64 @@ function panels_page_wizard_panels_cache_set($key, $cache) {
page_manager_set_wizard_cache($wizard_cache);
}
/**
* Alter the page wizard basic page, when panels is selected, to inject page
* manager as the storage plugin for panels.
* @param $form
* @param $form_state
*/
function panels_form_page_manager_page_form_basic_alter(&$form, &$form_state) {
$form['#validate'][] = 'panels_page_manager_handler_add_validate';
}
/**
* Alter the variant add page, so when panels is selected, page manager is the
* storage plugin for panels.
* @param $form
* @param $form_state
*/
function panels_form_page_manager_handler_add_alter(&$form, &$form_state) {
$form['#validate'][] = 'panels_page_manager_handler_add_validate';
}
/**
* Perform the validation check to see if panel context is selected to use
* page manager as the storage plugin.
* @param $form
* @param $form_state
*/
function panels_page_manager_handler_add_validate($form, &$form_state) {
if($form_state['values']['handler'] == 'panel_context') {
$form_state['page']->storage_type = 'page_manager';
}
}
/**
* Implements hook_default_page_manager_handlers_alter().
*
* If a default Panels display has no storage type, set it.
*/
function panels_default_page_manager_handlers_alter(&$handlers) {
foreach ($handlers as &$handler) {
if ($handler->handler == 'panel_context') {
$display =& $handler->conf['display'];
if (empty($display->storage_type)) {
$display->storage_type = 'page_manager';
$display->storage_id = $handler->name;
}
}
}
}
/**
* Implements hook_default_page_manager_pages_alter().
*/
function panels_default_page_manager_pages_alter(&$pages) {
foreach ($pages as &$page) {
panels_default_page_manager_handlers_alter($page->default_handlers);
}
}
// --------------------------------------------------------------------------
// General utility functions
@@ -1744,6 +1897,98 @@ function _panels_builder_filter($layout) {
return empty($layout['builder']);
}
/**
* Implements hook_get_pane_links_alter().
*
* add links to the Panels pane dropdown menu.
*/
function panels_get_pane_links_alter(&$links, $pane, $content_type) {
if ($pane->type === "block"){
$prefixed_name = $pane->subtype;
// breakup the subtype string into parts.
$exploded_subtype = explode('-', $pane->subtype);
// get the first part of the string.
$subtype_prefix = $exploded_subtype[0];
// get the first part of the string and add a hyphen.
$subtype_prefix_hyphen = $exploded_subtype[0] . '-';
// remove the prefix block- to get the name.
$name_of_block = ltrim( $prefixed_name, $subtype_prefix_hyphen);
// check for user added menus created at /admin/structure/menu/add
// menus of that type have a subtype that is prefixed with menu-menu-
if (substr($prefixed_name, 0, 10) === "menu-menu-"){
// remove the first prefix menu- from menu-menu- to get the name.
$name_of_block = substr($prefixed_name, 5);
$links['top'][] = array(
'title' => t('Edit block'),
'href' => url('admin/structure/block/manage/' . $subtype_prefix . '/' . $name_of_block . '/configure', array('absolute' => TRUE)),
'attributes' => array('target' => array('_blank')),
);
$links['top'][] = array(
'title' => t('Edit menu links'),
'href' => url('admin/structure/menu/manage/' . $name_of_block, array('absolute' => TRUE)),
'attributes' => array('target' => array('_blank')),
);
}
// check for module provided menu blocks like Devels or Features
// menus of that type have a subtype that is prefixed with menu-
elseif(substr($prefixed_name, 0, 5) === "menu-"){
// remove the first prefix menu- to get the name.
$name_of_block = substr($prefixed_name, 5);
$links['top'][] = array(
'title' => t('Edit block'),
'href' => url('admin/structure/block/manage/' . $subtype_prefix . '/' . $name_of_block . '/configure', array('absolute' => TRUE)),
'attributes' => array('target' => array('_blank')),
);
$links['top'][] = array(
'title' => t('Edit menu links'),
'href' => url('admin/structure/menu/manage/' . $name_of_block, array('absolute' => TRUE)),
'attributes' => array('target' => array('_blank')),
);
}
// check for system blocks with menu links
elseif(substr($prefixed_name, 0, 7) === "system-") {
// remove the first prefix system- to get the name
$name_of_block = substr($prefixed_name, 7);
$names_of_system_menus = menu_list_system_menus();
$links['top'][] = array(
'title' => t('Edit block'),
'href' => url('admin/structure/block/manage/' . $subtype_prefix . '/' . $name_of_block . '/configure', array('absolute' => TRUE)),
'attributes' => array('target' => array('_blank')),
);
if (array_key_exists($name_of_block, $names_of_system_menus)){
$links['top'][] = array(
'title' => t('Edit menu links'),
'href' => url('admin/structure/menu/manage/' . $name_of_block, array('absolute' => TRUE)),
'attributes' => array('target' => array('_blank')),
);
}
}
// for all other blocks without menus
else{
$links['top'][] = array(
'title' => t('Edit block'),
'href' => url('admin/structure/block/manage/' . $subtype_prefix . '/' . $name_of_block . '/configure', array('absolute' => TRUE)),
'attributes' => array('target' => array('_blank')),
);
}
}
}
// --------------------------------------------------------------------------
// Deprecated functions
//
@@ -1763,7 +2008,7 @@ function panels_get_path($file, $base_path = FALSE, $module = 'panels') {
function panels_preprocess_html(&$vars) {
$panel_body_css = &drupal_static('panel_body_css');
if (!empty($panel_body_css['body_classes_to_remove'])) {
$classes_to_remove = explode(' ', $panel_body_css['body_classes_to_remove']);
$classes_to_remove = array_filter(explode(' ', $panel_body_css['body_classes_to_remove']), 'strlen');
foreach ($vars['classes_array'] as $key => $css_class) {
if (in_array($css_class, $classes_to_remove)) {
unset($vars['classes_array'][$key]);

View File

@@ -49,8 +49,8 @@ div.panels-ipe-control .form-submit {
padding: 0 34px 2px 0.8em;
}
input#panels-ipe-save,
input#panels-ipe-cancel {
#panels-ipe-save,
#panels-ipe-cancel {
background-position: 86% 0;
}

View File

@@ -241,7 +241,9 @@ div.panels-ipe-handlebar-wrapper li.delete a span {
div.panels-ipe-handlebar-wrapper li a:hover,
div.panels-ipe-dragtitle span:hover,
div.panels-ipe-newblock a:hover,
span.panels-ipe-draghandle-icon:hover {
span.panels-ipe-draghandle-icon:hover,
div.panels-ipe-handlebar-wrapper li a:focus,
div.panels-ipe-newblock a:focus {
background: #E6E6E6;
background-image: linear-gradient(bottom, #C5C5C5 0%, #FAFAFA 100%);
background-image: -o-linear-gradient(bottom, #C5C5C5 0%, #FAFAFA 100%);
@@ -382,6 +384,7 @@ div.panels-ipe-control .form-submit {
div.panels-ipe-control input.panels-ipe-save, div.panels-ipe-control input.panels-ipe-cancel,
div.panels-ipe-control input.panels-ipe-save:hover, div.panels-ipe-control input.panels-ipe-cancel:hover,
div.panels-ipe-control input.panels-ipe-save:focus, div.panels-ipe-control input.panels-ipe-cancel:focus,
div.panels-ipe-control input.panels-ipe-save:active, div.panels-ipe-control input.panels-ipe-cancel:active {
background-repeat: no-repeat;
}
@@ -394,7 +397,7 @@ div.panels-ipe-pseudobutton-container a {
text-decoration: none;
}
div.panels-ipe-control input.panels-ipe-save {
div.panels-ipe-control .panels-ipe-save {
background-image: url(../images/icon-save.png);
background-image: url(../images/icon-save.png), linear-gradient(bottom, #383838 0%, #666666 100%);
background-image: url(../images/icon-save.png), -o-linear-gradient(bottom, #383838 0%, #666666 100%);
@@ -411,7 +414,7 @@ div.panels-ipe-control input.panels-ipe-save {
);
}
div.panels-ipe-control input.panels-ipe-cancel {
div.panels-ipe-control .panels-ipe-cancel {
background-image: url(../images/icon-close.png);
background-image: url(../images/icon-close.png), linear-gradient(bottom, #383838 0%, #666666 100%);
background-image: url(../images/icon-close.png), -o-linear-gradient(bottom, #383838 0%, #666666 100%);
@@ -429,7 +432,9 @@ div.panels-ipe-control input.panels-ipe-cancel {
}
div.panels-ipe-pseudobutton-container:hover,
div.panels-ipe-control .form-submit:hover {
div.panels-ipe-control .form-submit:hover,
div.panels-ipe-pseudobutton-container:focus,
div.panels-ipe-control .form-submit:focus {
background: #999999;
background-image: linear-gradient(bottom, #3D3D3D 0%, #999999 100%);
background-image: -o-linear-gradient(bottom, #3D3D3D 0%, #999999 100%);
@@ -447,11 +452,13 @@ div.panels-ipe-control .form-submit:hover {
color: #FFF;
}
div.panels-ipe-pseudobutton-container a:hover {
div.panels-ipe-pseudobutton-container a:hover,
div.panels-ipe-pseudobutton-container a:focus {
color: #FFF;
}
div.panels-ipe-control input.panels-ipe-cancel:hover {
div.panels-ipe-control .panels-ipe-cancel:hover,
div.panels-ipe-control .panels-ipe-cancel:focus {
background-image: url(../images/icon-close.png), linear-gradient(bottom, #3D3D3D 0%, #999999 100%);
background-image: url(../images/icon-close.png), -o-linear-gradient(bottom, #3D3D3D 0%, #999999 100%);
background-image: url(../images/icon-close.png), -moz-linear-gradient(bottom, #3D3D3D 0%, #999999 100%);
@@ -467,7 +474,8 @@ div.panels-ipe-control input.panels-ipe-cancel:hover {
);
}
div.panels-ipe-control input.panels-ipe-save:hover {
div.panels-ipe-control .panels-ipe-save:hover,
div.panels-ipe-control .panels-ipe-save:focus {
background-image: url(../images/icon-save.png), linear-gradient(bottom, #3D3D3D 0%, #999999 100%);
background-image: url(../images/icon-save.png), -o-linear-gradient(bottom, #3D3D3D 0%, #999999 100%);
background-image: url(../images/icon-save.png), -moz-linear-gradient(bottom, #3D3D3D 0%, #999999 100%);
@@ -507,7 +515,7 @@ div.panels-ipe-pseudobutton-container a:active {
color: #CCC;
}
div.panels-ipe-control input.panels-ipe-cancel:active {
div.panels-ipe-control .panels-ipe-cancel:active {
background-image: url(../images/icon-close.png), linear-gradient(bottom, #616161 0%, #333333 100%);
background-image: url(../images/icon-close.png), -o-linear-gradient(bottom, #616161 0%, #333333 100%);
background-image: url(../images/icon-close.png), -moz-linear-gradient(bottom, #616161 0%, #333333 100%);
@@ -523,7 +531,7 @@ div.panels-ipe-control input.panels-ipe-cancel:active {
);
}
div.panels-ipe-control input.panels-ipe-save:active {
div.panels-ipe-control .panels-ipe-save:active {
background-image: url(../images/icon-save.png), linear-gradient(bottom, #616161 0%, #333333 100%);
background-image: url(../images/icon-save.png), -o-linear-gradient(bottom, #616161 0%, #333333 100%);
background-image: url(../images/icon-save.png), -moz-linear-gradient(bottom, #616161 0%, #333333 100%);
@@ -539,6 +547,12 @@ div.panels-ipe-control input.panels-ipe-save:active {
);
}
div.panels-ipe-control .panels-ipe-save, div.panels-ipe-control .panels-ipe-cancel,
div.panels-ipe-control .panels-ipe-save:hover, div.panels-ipe-control .panels-ipe-cancel:hover,
div.panels-ipe-control .panels-ipe-save:active, div.panels-ipe-control .panels-ipe-cancel:active {
background-repeat: no-repeat;
}
div.panels-ipe-pseudobutton-container a.panels-ipe-startedit {
padding-left: 34px;
background: url(../images/icon-configure.png) no-repeat 10px 9px;
@@ -557,3 +571,7 @@ div.panels-ipe-button-container {
form#panels-ipe-edit-control-form {
text-align: center;
}
.panels-ipe-dragbar-admin-title{
font-size: 0.9em;
}

View File

@@ -2,12 +2,7 @@
// Ensure the $ alias is owned by jQuery.
(function($) {
// randomly lock a pane.
// @debug only
Drupal.settings.Panels = Drupal.settings.Panels || {};
Drupal.settings.Panels.RegionLock = {
10: { 'top': false, 'left': true, 'middle': true }
}
Drupal.PanelsIPE = {
editors: {},
@@ -31,6 +26,17 @@ Drupal.PanelsIPE = {
Drupal.behaviors.PanelsIPE = {
attach: function(context) {
// Remove any old editors.
for (var i in Drupal.PanelsIPE.editors) {
if (Drupal.settings.PanelsIPECacheKeys.indexOf(i) === -1) {
// Clean-up a little bit and remove it.
Drupal.PanelsIPE.editors[i].editing = false;
Drupal.PanelsIPE.editors[i].changed = false;
delete Drupal.PanelsIPE.editors[i];
}
}
// Initialize new editors.
for (var i in Drupal.settings.PanelsIPECacheKeys) {
var key = Drupal.settings.PanelsIPECacheKeys[i];
$('div#panels-ipe-display-' + key + ':not(.panels-ipe-processed)')
@@ -213,9 +219,11 @@ function DrupalPanelsIPE(cache_key, cfg) {
$('div.panels-ipe-sort-container', ipe.topParent).bind('sortstop', this.enableRegions);
// Refresh the control jQuery object.
ipe.control = $(ipe.control.selector);
$('.panels-ipe-form-container', ipe.control).append(formdata);
$('input:submit:not(.ajax-processed)', ipe.control).addClass('ajax-processed').each(function() {
$('input:submit:not(.ajax-processed), button:not(.ajax-processed)', ipe.control).addClass('ajax-processed').each(function() {
var element_settings = {};
element_settings.url = $(this.form).attr('action');
@@ -233,7 +241,7 @@ function DrupalPanelsIPE(cache_key, cfg) {
// it clears out inline styles.
$('.panels-ipe-on').show();
ipe.showForm();
ipe.topParent.addClass('panels-ipe-editing');
$('body').add(ipe.topParent).addClass('panels-ipe-editing');
};
@@ -264,12 +272,16 @@ function DrupalPanelsIPE(cache_key, cfg) {
// Re-show all the IPE non-editing meta-elements
$('div.panels-ipe-off').show('fast');
// Refresh the container and control jQuery objects.
ipe.container = $(ipe.container.selector);
ipe.control = $(ipe.control.selector);
ipe.showButtons();
// Re-hide all the IPE meta-elements
$('div.panels-ipe-on').hide();
$('.panels-ipe-editing').removeClass('panels-ipe-editing');
$('div.panels-ipe-sort-container', ipe.topParent).sortable("destroy");
$('div.panels-ipe-sort-container.ui-sortable', ipe.topParent).sortable("destroy");
};
this.saveEditing = function() {
@@ -285,7 +297,7 @@ function DrupalPanelsIPE(cache_key, cfg) {
val += id;
}
});
$('input[name="panel[pane][' + region + ']"]', ipe.control).val(val);
$('[name="panel[pane][' + region + ']"]', ipe.control).val(val);
});
}
@@ -322,7 +334,7 @@ function DrupalPanelsIPE(cache_key, cfg) {
this.createSortContainers = function() {
$('div.panels-ipe-region', this.topParent).each(function() {
$('div.panels-ipe-portlet-marker', this).parent()
$(this).children('div.panels-ipe-portlet-marker').parent()
.wrapInner('<div class="panels-ipe-sort-container" />');
// Move our gadgets outside of the sort container so that sortables
@@ -330,9 +342,6 @@ function DrupalPanelsIPE(cache_key, cfg) {
$('div.panels-ipe-portlet-static', this).each(function() {
$(this).prependTo($(this).parent().parent());
});
// Also remove the last panel separator.
$('div.panel-separator', this).filter(':last').remove();
});
}
@@ -386,6 +395,34 @@ $(function() {
}
};
Drupal.ajax.prototype.commands.insertNewPane = function(ajax, data, status) {
IPEContainerSelector = '#panels-ipe-regionid-' + data.regionId + ' div.panels-ipe-sort-container';
firstPaneSelector = IPEContainerSelector + ' div.panels-ipe-portlet-wrapper:first';
// Insert the new pane before the first existing pane in the region, if
// any.
if ($(firstPaneSelector).length) {
insertData = {
'method': 'before',
'selector': firstPaneSelector,
'data': data.renderedPane,
'settings': null
}
Drupal.ajax.prototype.commands.insert(ajax, insertData, status);
}
// Else, insert it as a first child of the container. Doing so might fall
// outside of the wrapping markup for the style, but it's the best we can
// do.
else {
insertData = {
'method': 'prepend',
'selector': IPEContainerSelector,
'data': data.renderedPane,
'settings': null
}
Drupal.ajax.prototype.commands.insert(ajax, insertData, status);
}
};
/**
* Override the eventResponse on ajax.js so we can add a little extra
* behavior.

View File

@@ -0,0 +1,31 @@
<?php
/**
* @file
* Hooks provided by Panels In-Place Editor.
*/
/**
* Allow modules to control access to the Panels IPE.
*
* @param panels_display $display
* The panels display about to be rendered.
*
* @return TRUE|FALSE|NULL
* Returns TRUE to allow access, FALSE to deny, or NULL if the module
* implementing this hook doesn't care about access for the given display.
*/
function hook_panels_ipe_access(panels_display $display) {
// We only care about displays with the 'panelizer' context.
if (!isset($display->context['panelizer'])) {
return NULL;
}
if ($display->context['panelizer']->type[0] == 'entity:node') {
// Allow or deny IPE access based on node type.
return $display->context['panelizer']->data->type == 'awesome_page';
}
// Otherwise, deny access to everything!
return FALSE;
}

View File

@@ -1,14 +1,15 @@
name = Panels In-Place Editor
description = Provide a UI for managing some Panels directly on the frontend, instead of having to use the backend.
package = "Panels"
version = PANELS_VERSION
dependencies[] = panels
core = 7.x
configure = admin/structure/panels
files[] = panels_ipe.module
; Information added by drupal.org packaging script on 2013-03-02
version = "7.x-3.3+39-dev"
; Information added by Drupal.org packaging script on 2016-08-20
version = "7.x-3.7"
core = "7.x"
project = "panels"
datestamp = "1362187383"
datestamp = "1471704242"

View File

@@ -133,18 +133,22 @@ function template_preprocess_panels_ipe_pane_wrapper(&$vars) {
function theme_panels_ipe_pane_wrapper($vars) {
$output = $vars['output'];
$pane = $vars['pane'];
$display = $vars['display'];
$attributes = array(
'class' => 'panels-ipe-linkbar',
);
$type = ctools_get_content_type($pane->type);
$title ='<span class = "panels-ipe-dragbar-admin-title">' . ctools_content_admin_title($type, $pane->subtype, $pane->configuration, $display->context) . '</span>';
$links = theme('links', array('links' => $vars['links'], 'attributes' => $attributes));
if (!empty($pane->locks['type']) && $pane->locks['type'] == 'immovable') {
$links = '<div class="panels-ipe-dragbar panels-ipe-nodraghandle clearfix">' . $links . '</div>';
$links = '<div class="panels-ipe-dragbar panels-ipe-nodraghandle clearfix">' . $links .$title .'</div>';
}
else {
$links = '<div class="panels-ipe-dragbar panels-ipe-draghandle clearfix">' . $links . '<span class="panels-ipe-draghandle-icon"><span class="panels-ipe-draghandle-icon-inner"></span></span></div>';
$links = '<div class="panels-ipe-dragbar panels-ipe-draghandle clearfix">' . $links . $title . '<span class="panels-ipe-draghandle-icon"><span class="panels-ipe-draghandle-icon-inner"></span></span></div>';
}
$handlebar = '<div class="panels-ipe-handlebar-wrapper panels-ipe-on">' . $links . '</div>';
@@ -217,6 +221,7 @@ function panels_ipe_get_cache_key($key = NULL) {
*/
function panels_ipe_toolbar_add_button($cache_key, $id, $button) {
$buttons = &drupal_static('panels_ipe_toolbar_buttons', array());
drupal_alter('panels_ipe_button', $button, $id, $cache_key);
$buttons[$cache_key][$id] = $button;
}
@@ -242,9 +247,11 @@ function panels_ipe_page_alter(&$page) {
function theme_panels_ipe_toolbar($vars) {
$buttons = $vars['buttons'];
ctools_include('cleanstring');
$output = "<div id='panels-ipe-control-container' class='clearfix'>";
foreach ($buttons as $key => $ipe_buttons) {
$key = ctools_cleanstring($key);
$output .= "<div id='panels-ipe-control-$key' class='panels-ipe-control'>";
// Controls in this container will appear when the IPE is not on.

View File

@@ -7,12 +7,44 @@ class panels_renderer_ipe extends panels_renderer_editor {
// The IPE operates in normal render mode, not admin mode.
var $admin = FALSE;
// Whether or not the user has access.
var $access = NULL;
function invoke_panels_ipe_access() {
if (user_access('bypass access in place editing')) {
return TRUE;
}
// Modules can return TRUE, FALSE or NULL, for allowed, disallowed,
// or don't care - respectively. On the first FALSE, we deny access,
// otherwise allow.
foreach (module_invoke_all('panels_ipe_access', $this->display) as $result) {
if ($result === FALSE) {
return FALSE;
}
}
return TRUE;
}
function access() {
if (is_null($this->access)) {
$this->access = $this->invoke_panels_ipe_access();
}
return $this->access;
}
function render() {
$output = parent::render();
return "<div id='panels-ipe-display-{$this->clean_key}' class='panels-ipe-display-container'>$output</div>";
if ($this->access()) {
return "<div id='panels-ipe-display-{$this->clean_key}' class='panels-ipe-display-container'>$output</div>";
}
return $output;
}
function add_meta() {
if (!$this->access()) {
return parent::add_meta();
}
ctools_include('display-edit', 'panels');
ctools_include('content');
@@ -29,6 +61,7 @@ class panels_renderer_ipe extends panels_renderer_editor {
'#type' => 'link',
'#title' => t('Customize this page'),
'#href' => $this->get_url('save_form'),
'#options' => array('query' => drupal_get_destination()),
'#id' => 'panels-ipe-customize-page',
'#attributes' => array(
'class' => array('panels-ipe-startedit', 'panels-ipe-pseudobutton'),
@@ -41,7 +74,7 @@ class panels_renderer_ipe extends panels_renderer_editor {
'#suffix' => '</div>',
);
panels_ipe_toolbar_add_button($this->clean_key, 'panels-ipe-startedit', $button);
panels_ipe_toolbar_add_button($this->display->cache_key, 'panels-ipe-startedit', $button);
// @todo this actually should be an IPE setting instead.
if (user_access('change layouts in place editing')) {
@@ -49,6 +82,7 @@ class panels_renderer_ipe extends panels_renderer_editor {
'#type' => 'link',
'#title' => t('Change layout'),
'#href' => $this->get_url('change_layout'),
'#options' => array('query' => drupal_get_destination()),
'#attributes' => array(
'class' => array('panels-ipe-change-layout', 'panels-ipe-pseudobutton', 'ctools-modal-layout'),
),
@@ -61,7 +95,7 @@ class panels_renderer_ipe extends panels_renderer_editor {
'#suffix' => '</div>',
);
panels_ipe_toolbar_add_button($this->clean_key, 'panels-ipe-change-layout', $button);
panels_ipe_toolbar_add_button($this->display->cache_key, 'panels-ipe-change-layout', $button);
}
ctools_include('ajax');
@@ -70,6 +104,7 @@ class panels_renderer_ipe extends panels_renderer_editor {
ctools_add_css('panels_dnd', 'panels');
ctools_add_css('panels_admin', 'panels');
ctools_add_js('panels-base', 'panels');
ctools_add_js('panels_ipe', 'panels_ipe');
ctools_add_css('panels_ipe', 'panels_ipe');
@@ -93,6 +128,9 @@ class panels_renderer_ipe extends panels_renderer_editor {
if (empty($output)) {
return;
}
if (!$this->access()) {
return $output;
}
// If there are region locks, add them.
if (!empty($pane->locks['type']) && $pane->locks['type'] == 'regions') {
@@ -135,6 +173,10 @@ class panels_renderer_ipe extends panels_renderer_editor {
}
function prepare_panes($panes) {
if (!$this->access()) {
return parent::prepare_panes($panes);
}
// Set to admin mode just for this to ensure all panes are represented.
$this->admin = TRUE;
$panes = parent::prepare_panes($panes);
@@ -142,6 +184,10 @@ class panels_renderer_ipe extends panels_renderer_editor {
}
function render_pane_content(&$pane) {
if (!$this->access()) {
return parent::render_pane_content($pane);
}
if (!empty($pane->shown) && panels_pane_access($pane, $this->display)) {
$content = parent::render_pane_content($pane);
}
@@ -172,6 +218,10 @@ class panels_renderer_ipe extends panels_renderer_editor {
* @param $panes
*/
function render_region($region_id, $panes) {
if (!$this->access()) {
return parent::render_region($region_id, $panes);
}
// Generate this region's 'empty' placeholder pane from the IPE plugin.
$empty_ph = theme('panels_ipe_placeholder_pane', array('region_id' => $region_id, 'region_title' => $this->plugins['layout']['regions'][$region_id]));
@@ -209,6 +259,19 @@ class panels_renderer_ipe extends panels_renderer_editor {
// Break the lock.
panels_edit_cache_break_lock($this->cache);
}
}
function get_panels_storage_op_for_ajax($method) {
switch ($method) {
case 'ajax_unlock_ipe':
case 'ajax_save_form':
return 'update';
case 'ajax_change_layout':
case 'ajax_set_layout':
return 'change layout';
}
return parent::get_panels_storage_op_for_ajax($method);
}
/**
@@ -282,6 +345,9 @@ class panels_renderer_ipe extends panels_renderer_editor {
// rendered.
$this->meta_location = 'inline';
$this->commands[] = ajax_command_replace("#panels-ipe-display-{$this->clean_key}", panels_render_display($this->display, $this));
$buttons = &drupal_static('panels_ipe_toolbar_buttons', array());
$output = theme('panels_ipe_toolbar', array('buttons' => $buttons));
$this->commands[] = ajax_command_replace('#panels-ipe-control-container', $output);
}
else {
// Cancelled. Clear the cache.
@@ -320,6 +386,9 @@ class panels_renderer_ipe extends panels_renderer_editor {
// Filter out builders
$layouts = array_filter($layouts, '_panels_builder_filter');
// Let other modules filter the layouts.
drupal_alter('panels_layouts_available', $layouts);
// Define the current layout
$current_layout = $this->plugins['layout']['name'];
@@ -358,7 +427,7 @@ class panels_renderer_ipe extends panels_renderer_editor {
if (!empty($form_state['clicked_button']['#save-display'])) {
// Saved. Save the cache.
panels_edit_cache_save($this->cache);
$this->display->skip_cache;
$this->display->skip_cache = TRUE;
// Since the layout changed, we have to update these things in the
// renderer in order to get the right settings.
@@ -405,7 +474,11 @@ class panels_renderer_ipe extends panels_renderer_editor {
$pane = $this->display->content[$pid];
}
$this->commands[] = ajax_command_prepend("#panels-ipe-regionid-{$pane->panel} div.panels-ipe-sort-container", $this->render_pane($pane));
$this->commands[] = array(
'command' => 'insertNewPane',
'regionId' => $pane->panel,
'renderedPane' => $this->render_pane($pane),
);
$this->commands[] = ajax_command_changed("#panels-ipe-display-{$this->clean_key}");
$this->commands[] = array(
'command' => 'addNewPane',

View File

@@ -0,0 +1,12 @@
/**
* @file
* Custom CSS for the Mini Panels module.
*/
/**
* Customize the CTools wizard trail / breadcrumb used on the edit pages for
* Mini Panels as a stop-gap measure until the UX can be completely re-done.
*/
.wizard-trail {
text-align: right;
}

View File

@@ -1,12 +1,13 @@
name = Mini panels
description = Create mini panels that can be used as blocks by Drupal and panes by other panel modules.
package = "Panels"
version = PANELS_VERSION
dependencies[] = panels
core = 7.x
files[] = plugins/export_ui/panels_mini_ui.class.php
; Information added by drupal.org packaging script on 2013-03-02
version = "7.x-3.3+39-dev"
; Information added by Drupal.org packaging script on 2016-08-20
version = "7.x-3.7"
core = "7.x"
project = "panels"
datestamp = "1362187383"
datestamp = "1471704242"

View File

@@ -114,7 +114,7 @@ function panels_mini_uninstall() {
$deltas[] = $panel_mini->pid;
}
if ($deltas) {
if (db_table_exists('block') && $deltas) {
// Delete all configured blocks.
db_delete('block')
->condition('module', 'panels_mini')
@@ -122,3 +122,61 @@ function panels_mini_uninstall() {
->execute();
}
}
/**
* Implements hook_update_dependencies().
*/
function panels_mini_update_dependencies() {
// Update 7301 requires panels storage support
$dependencies['panels_mini'][7301] = array(
'panels' => 7305,
);
return $dependencies;
}
/**
* Set the storage type and id on existing mini panels.
*/
function panels_mini_update_7301() {
if (!isset($sandbox['progress'])) {
// Initialize batch update information.
$sandbox['progress'] = (float)0;
$sandbox['current_did'] = -1;
$sandbox['max'] = db_query("SELECT COUNT(pd.did)
FROM {panels_display} pd
JOIN {panels_mini} pm ON pm.did = pd.did
WHERE pd.storage_type = ''")->fetchField();
}
// Set a limit of how many rows to process per batch.
$limit = 1000;
// Run the query
$result = db_query_range("SELECT pd.did, pm.name
FROM {panels_display} pd
JOIN {panels_mini} pm ON pm.did = pd.did
WHERE pd.storage_type = '' AND pd.did > :current_did", 0, $limit, array(':current_did' => $sandbox['current_did']));
foreach ($result as $row) {
db_update('panels_display')
->fields(array(
'storage_type' => 'panels_mini',
'storage_id' => $row->name,
))
->condition('did', $row->did)
->execute();
// Update our progress information.
$sandbox['progress']++;
$sandbox['current_did'] = $row->did;
}
// Set the "finished" status, to tell batch engine whether this function
// needs to run again.
$sandbox['#finished'] = ($sandbox['progress'] >= $sandbox['max']) ? TRUE : ($sandbox['progress'] / $sandbox['max']);
if ($sandbox['#finished']) {
return t('Added the storage type for panels_mini to relevant panels displays');
}
}

View File

@@ -112,9 +112,11 @@ function panels_mini_block_view($delta = 0) {
$contexts = ctools_context_match_required_contexts($panel_mini->requiredcontexts, $current_page['contexts']);
}
}
drupal_alter('panels_mini_block_contexts', $contexts, $panel_mini);
$panel_mini->context = $panel_mini->display->context = ctools_context_load_contexts($panel_mini, FALSE, $contexts);
$panel_mini->display->css_id = panels_mini_get_id($panel_mini->name);
$panel_mini->display->owner = $panel_mini;
$block = array();
@@ -145,6 +147,10 @@ function panels_mini_block_list_alter(&$blocks) {
if (module_exists('page_manager')) {
$current_page = page_manager_get_current_page();
}
// Load add at once to save time.
panels_mini_load_all();
foreach ($blocks as $key => $block) {
if ($block->module != 'panels_mini') {
// This block was added by a contrib module, leave it in the list.
@@ -178,6 +184,44 @@ function panels_mini_block_list_alter(&$blocks) {
}
}
/**
* Implements hook_get_pane_links_alter().
*/
function panels_mini_get_pane_links_alter(&$links, $pane, $content_type) {
if ($pane->type == 'panels_mini') {
$links['top']['edit_panels_mini'] = array(
'title' => t('Edit mini panel'),
'href' => url('admin/structure/mini-panels/list/' . $pane->subtype . '/edit/content', array('absolute' => TRUE)),
'attributes' => array('target' => array('_blank')),
);
}
}
/**
* Implements hook_contextual_links_view_alter().
*/
function panels_mini_contextual_links_view_alter(&$element, $items) {
// Add contextual links to all mini panel blocks with bid property.
if (isset($element['#element']['#block']) && isset($element['#element']['#block']->bid) && strpos((string) $element['#element']['#block']->bid, 'panels_mini') === 0) {
$admin_pages = array(
t('Configure mini panel settings') => 'basic',
t('Configure mini panel context') => 'context',
t('Configure mini panel layout') => 'layout',
t('Configure mini panel content') => 'content',
);
foreach ($admin_pages as $title => $tail) {
$element['#links']['mini-panels-' . $tail] = array(
'title' => $title,
'href' => 'admin/structure/mini-panels/list/' . $element['#element']['#block']->delta . '/edit/' . $tail,
'query' => drupal_get_destination(),
);
}
}
}
/**
* Statically store all used IDs to ensure all mini panels get a unique id.
*/
@@ -215,22 +259,30 @@ function panels_mini_load($name) {
// We use array_key_exists because failed loads will be NULL and
// isset() will try to load it again.
if (!array_key_exists($name, $cache)) {
ctools_include('export');
$result = ctools_export_load_object('panels_mini', 'names', array($name));
if (isset($result[$name])) {
if (empty($result[$name]->display)) {
$result[$name]->display = panels_load_display($result[$name]->did);
if (!empty($result[$name]->title) && empty($result[$name]->display->title)) {
$result[$name]->display->title = $result[$name]->title;
}
}
$cache[$name] = $result[$name];
if (!empty($result[$name]->title) && empty($result[$name]->admin_title)) {
$cache[$name]->admin_title = $result[$name]->title;
}
$cid = 'panels_mini_load:' . $name;
$result = cache_get($cid, 'cache_panels');
if (!empty($result->data)) {
$cache[$name] = $result->data;
}
else {
$cache[$name] = NULL;
ctools_include('export');
$result = ctools_export_load_object('panels_mini', 'names', array($name));
if (isset($result[$name])) {
if (empty($result[$name]->display)) {
$result[$name]->display = panels_load_display($result[$name]->did);
if (!empty($result[$name]->title) && empty($result[$name]->display->title)) {
$result[$name]->display->title = $result[$name]->title;
}
}
$cache[$name] = $result[$name];
if (!empty($result[$name]->title) && empty($result[$name]->admin_title)) {
$cache[$name]->admin_title = $result[$name]->title;
}
cache_set($cid, $cache[$name], 'cache_panels', CACHE_TEMPORARY);
}
else {
$cache[$name] = NULL;
}
}
}
@@ -253,6 +305,22 @@ function panels_mini_load_all($reset = FALSE) {
if ($reset) {
$cache = array();
}
else {
$panel_names = db_select('panels_mini', 'pm')
->fields('pm', array('name'))
->execute();
$cids = array();
foreach ($panel_names as $name) {
$cids[] = 'panels_mini_load:' . $name->name;
}
$output = cache_get_multiple($cids, 'cache_panels');
foreach ($output as $mini) {
if (!empty($mini->data)) {
$mini = $mini->data;
$cache[$mini->name] = $mini;
}
}
}
ctools_include('export');
$minis = ctools_export_load_object('panels_mini');
@@ -294,10 +362,14 @@ function panels_mini_load_all($reset = FALSE) {
*/
function panels_mini_save(&$mini) {
if (!empty($mini->display)) {
$mini->display->storage_id = $mini->name;
$display = panels_save_display($mini->display);
$mini->did = $display->did;
}
// Clear the panels_mini_load cache.
cache_clear_all('panels_mini_load:', 'cache_panels', TRUE);
$update = (isset($mini->pid) && $mini->pid != 'new') ? array('pid') : array();
drupal_write_record('panels_mini', $mini, $update);
@@ -350,6 +422,24 @@ function panels_mini_ctools_plugin_directory($module, $plugin) {
if ($module == 'ctools' && ($plugin == 'content_types' || $plugin == 'export_ui')) {
return 'plugins/' . $plugin;
}
if ($module == 'panels' && $plugin == 'panels_storage') {
return 'plugins/' . $plugin;
}
}
/**
* Implements hook_default_panels_mini_alter().
*
* If a default Panels display has no storage type, set it.
*/
function panels_default_panels_mini_alter(&$mini_panels) {
foreach ($mini_panels as &$mini_panel) {
$display =& $mini_panel->display;
if (empty($display->storage_type)) {
$display->storage_type = 'panels_mini';
$display->storage_id = $mini_panel->name;
}
}
}
/**
@@ -388,6 +478,9 @@ function panels_mini_panels_cache_get($key) {
$cache->display = $item->display;
$cache->display->context = ctools_context_load_contexts($item);
$cache->display->cache_key = 'panels_mini:' . $key;
$cache->display->storage_type = 'panels_mini';
// Temporary storage id that's replaced in panels_mini_save().
$cache->display->storage_id = 'panels_mini';
$cache->content_types = panels_common_get_allowed_types('panels_mini', $cache->display->context);
$cache->display_title = TRUE;
@@ -431,6 +524,15 @@ function panels_mini_panels_cache_save($key, $cache) {
function panels_mini_panels_cache_break_lock($key, $cache) {
}
/**
* Implements hook_panels_pre_render().
*/
function panels_mini_panels_pre_render($display, $renderer) {
if (isset($display->owner->table) && $display->owner->table == 'panels_mini' && $renderer instanceof panels_renderer_standard) {
$renderer->show_empty_layout = FALSE;
}
}
/**
* Implementation of hook_panels_dashboard_blocks().
*
@@ -480,3 +582,14 @@ function panels_mini_panels_dashboard_blocks(&$vars) {
);
}
/**
* Implements template_preprocess_ctools_wizard_trail().
*
* Customize the divider used in the CTools wizard to build the edit pages for
* Mini Panels as a stop-gap measure until the UX can be completely re-done.
*/
function panels_mini_preprocess_ctools_wizard_trail(&$variables) {
$variables['divider'] = ' | ';
drupal_add_css(drupal_get_path('module', 'panels_mini') . '/panels_mini.css');
}

View File

@@ -4,7 +4,7 @@
* @file
* Contains the content type plugin for a mini panel. While this does not
* need to be broken out into a .inc file, it's convenient that we do so
* that we don't load code unneccessarily. Plus it demonstrates plugins
* that we don't load code unnecessarily. Plus it demonstrates plugins
* in modules other than Panels itself.
*
*/
@@ -68,8 +68,13 @@ function _panels_mini_panels_mini_content_type_content_type($mini) {
$type['required context'] = array();
foreach ($mini->requiredcontexts as $context) {
$info = ctools_get_context($context['name']);
// TODO: allow an optional setting
$type['required context'][] = new ctools_context_required($context['identifier'], $info['context name']);
// Check if the required context is actually required.
if (!empty($context['optional'])) {
$type['required context'][] = new ctools_context_optional($context['identifier'], $info['context name']);
}
else {
$type['required context'][] = new ctools_context_required($context['identifier'], $info['context name']);
}
}
}
return $type;

View File

@@ -0,0 +1,22 @@
<?php
/**
* @file
* Provides a panels_storage plugin for mini panels.
*/
// Plugin definition
$plugin = array(
'access callback' => 'panels_mini_panels_storage_access',
);
/**
* Access callback for panels storage.
*/
function panels_mini_panels_storage_access($storage_type, $storage_id, $op, $account) {
if ($op == 'create') {
return user_access('create mini panels', $account);
}
return user_access('administer mini panels', $account);
}

View File

@@ -1,14 +1,15 @@
name = Panel nodes
description = Create nodes that are divided into areas with selectable content.
package = "Panels"
version = PANELS_VERSION
dependencies[] = panels
configure = admin/structure/panels
core = 7.x
files[] = panels_node.module
; Information added by drupal.org packaging script on 2013-03-02
version = "7.x-3.3+39-dev"
; Information added by Drupal.org packaging script on 2016-08-20
version = "7.x-3.7"
core = "7.x"
project = "panels"
datestamp = "1362187383"
datestamp = "1471704242"

View File

@@ -56,6 +56,18 @@ function panels_node_uninstall() {
drupal_uninstall_schema('panels_node');
}
/**
* Implements hook_update_dependencies().
*/
function panels_node_update_dependencies() {
// Update 7301 requires panels storage support
$dependencies['panels_node'][7301] = array(
'panels' => 7305,
);
return $dependencies;
}
/**
* Implementation of hook_update to handle adding a pipeline
*/
@@ -69,3 +81,87 @@ function panels_node_update_6001() {
db_add_field('panels_node', 'pipeline', $field);
return $ret;
}
/**
* Migrate legacy Drupal 6 permissions to Drupal 7.
*/
function panels_node_update_7301() {
$permissions = array(
'create panel-nodes' => 'create panel content',
'edit any panel-nodes' => 'edit any panel content',
'edit own panel-nodes' => 'edit own panel content',
'delete any panel-nodes' => 'delete any panel content',
'delete own panel-nodes' => 'delete own panel content',
);
foreach ($permissions as $legacy_permission => $new_permission) {
$query = db_select('role_permission', 'p')
->fields('p', array('rid'))
->condition('permission', $legacy_permission);
$rids = $query->execute()->fetchCol();
foreach ($rids as $rid) {
// Insert the new permission if it doesn't already exist.
db_merge('role_permission')
->key(array(
'rid' => $rid,
'permission' => $new_permission,
))
->insertFields(array(
'rid' => $rid,
'permission' => $new_permission,
'module' => 'node',
))
->execute();
}
// Delete the legacy permission.
db_delete('role_permission')
->condition('permission', $legacy_permission)
->execute();
}
}
/**
* Set the storage type and id on existing panels nodes.
*/
function panels_node_update_7302() {
if (!isset($sandbox['progress'])) {
// Initialize batch update information.
$sandbox['progress'] = (float)0;
$sandbox['current_did'] = -1;
$sandbox['max'] = db_query("SELECT COUNT(pd.did)
FROM {panels_display} pd
JOIN {panels_node} pn ON pn.did = pd.did
WHERE pd.storage_type = ''")->fetchField();
}
// Set a limit of how many rows to process per batch.
$limit = 1000;
// Run the query
$result = db_query_range("SELECT pd.did, pn.nid
FROM {panels_display} pd
JOIN {panels_node} pn ON pn.did = pd.did
WHERE pd.storage_type = '' AND pd.did > :current_did", 0, $limit, array(':current_did' => $sandbox['current_did']));
foreach ($result as $row) {
db_update('panels_display')
->fields(array(
'storage_type' => 'panels_node',
'storage_id' => $row->nid,
))
->condition('did', $row->did)
->execute();
// Update our progress information.
$sandbox['progress']++;
$sandbox['current_did'] = $row->did;
}
// Set the "finished" status, to tell batch engine whether this function
// needs to run again.
$sandbox['#finished'] = ($sandbox['progress'] >= $sandbox['max']) ? TRUE : ($sandbox['progress'] / $sandbox['max']);
if ($sandbox['#finished']) {
return t('Added the storage type for panels_node to relevant panels displays');
}
}

View File

@@ -17,33 +17,22 @@
*/
function panels_node_permission() {
return array(
'create panel-nodes' => array(
'title' => t('Create panel nodes'),
'description' => t('Create new panel nodes.'),
),
'edit any panel-nodes' => array(
'title' => t('Edit any panel-nodes'),
'description' => t('Edit all pre-existing panel nodes regardless of ownership.'),
),
'edit own panel-nodes' => array(
'title' => t('Edit own panel nodes'),
'description' => t('Edit panel nodes owned by this user.'),
),
'administer panel-nodes' => array(
'title' => t('Administer panel nodes'),
'description' => t('Full administrative access to panel nodes including create, update and delete all'),
),
'delete any panel-nodes' => array(
'title' => t('Delete any panel nodes'),
'description' => t('Delete any panel node regardless of ownership'),
),
'delete own panel-nodes' => array(
'title' => t('Delete own panel nodes'),
'description' => t('Delete any panel node owned by this user.'),
),
);
}
/**
* Implementation of hook_ctools_plugin_directory().
*/
function panels_node_ctools_plugin_directory($module, $plugin) {
if ($module == 'panels' && $plugin == 'panels_storage') {
return 'plugins/' . $plugin;
}
}
/**
* Implementation of hook_menu().
*/
@@ -83,7 +72,7 @@ function panels_node_menu() {
$items['node/add/panel/choose-layout'] = array(
'title' => 'Choose layout',
'access arguments' => array('create panel-nodes'),
'access callback' => 'panels_add_panel_access_callback',
'page callback' => 'panels_node_add',
'type' => MENU_CALLBACK,
);
@@ -102,6 +91,13 @@ function panels_node_edit_node($node) {
return node_access('update', $node);
}
/**
* Access callback to determine if user has access to add panel nodes.
*/
function panels_add_panel_access_callback() {
return user_access('create panel content') || user_access('administer panel-nodes');
}
/**
* Override of node add page to force layout selection prior
* to actually editing a node.
@@ -113,7 +109,7 @@ function panels_node_add() {
ctools_include('common', 'panels');
$layouts = panels_common_get_allowed_layouts('panels_node');
return panels_common_print_layout_links($layouts, 'node/add/panel', array('query' => $_GET));
return panels_common_print_layout_links($layouts, 'node/add/panel', array('query' => drupal_get_query_parameters()));
}
// ---------------------------------------------------------------------------
@@ -156,19 +152,6 @@ function panels_node_node_access($node, $op, $account) {
if (user_access('administer panel-nodes', $account)) {
return NODE_ACCESS_ALLOW;
}
if ($op == 'create' && user_access('create panel-nodes', $account)) {
return NODE_ACCESS_ALLOW;
}
if ($op == 'update' && (user_access('edit any panel-nodes', $account) || $node->uid == $account->uid && user_access('edit own panel-nodes', $account))) {
return NODE_ACCESS_ALLOW;
}
if ($op == 'delete' && (user_access('delete any panel-nodes') || $node->uid == $account->uid && user_access('delete own panel-nodes'))) {
return NODE_ACCESS_ALLOW;
}
}
/**
@@ -183,14 +166,12 @@ function panels_node_hook_form(&$node, &$form_state) {
// and if that doesn't work present them with a list to pick from.
$panel_layout = isset($node->panel_layout) ? $node->panel_layout : arg(3);
if (empty($panel_layout)) {
$opts = $_GET;
unset($opts['q']);
return drupal_goto('node/add/panel/choose-layout', $opts);
drupal_goto('node/add/panel/choose-layout', array('query' => drupal_get_query_parameters()));
}
$layout = panels_get_layout($panel_layout);
if (empty($layout)) {
return drupal_not_found();
return MENU_NOT_FOUND;
}
$form['panels_node']['layout'] = array(
'#type' => 'value',
@@ -233,7 +214,7 @@ function panels_node_hook_form(&$node, &$form_state) {
'#type' => 'radios',
'#options' => $options,
'#title' => t('Renderer'),
'#default_value' => isset($node->panels_node['pipeline']) ? $node->panels_node['pipeline'] : 'standard',
'#default_value' => isset($node->panels_node['pipeline']) ? $node->panels_node['pipeline'] : variable_get('panels_renderer_default', 'standard'),
);
return $form;
@@ -271,6 +252,8 @@ function panels_node_hook_insert(&$node) {
// Create a new display and record that.
$display = panels_new_display();
$display->layout = $node->panels_node['layout'];
$display->storage_type = 'panels_node';
$display->storage_id = $node->nid;
// Special handling for nodes being imported from an export.module data dump.
if (!empty($node->export_display)) {
@@ -431,6 +414,19 @@ function panels_node_panels_dashboard_blocks(&$vars) {
);
}
/**
* Implements hook_panels_ipe_access().
*/
function panels_node_panels_ipe_access($display) {
// We only care about Panels displays from panels_node.
if (isset($display->context['panel-node'])) {
// Only allow access to use the IPE if the user has 'update' access to
// the underlying node.
$node = $display->context['panel-node']->data;
return node_access('update', $node);
}
}
// ---------------------------------------------------------------------------
// Callbacks for panel caching.

View File

@@ -0,0 +1,25 @@
<?php
/**
* @file
* Provides a panels_storage plugin for panels node.
*/
// Plugin definition
$plugin = array(
'access callback' => 'panels_node_panels_storage_access',
);
/**
* Access callback for panels storage.
*/
function panels_node_panels_storage_access($storage_type, $storage_id, $op, $account) {
if ($node = node_load($storage_id)) {
if ($op == 'read') {
$op = 'view';
}
return node_access($op, $node, $account);
}
return FALSE;
}

View File

@@ -25,7 +25,7 @@ $plugin = array(
*/
function panels_simple_cache_get_cache($conf, $display, $args, $contexts, $pane = NULL) {
$cid = panels_simple_cache_get_id($conf, $display, $args, $contexts, $pane);
$cache = cache_get($cid, 'cache');
$cache = cache_get($cid, 'cache_panels');
if (!$cache) {
return FALSE;
}
@@ -42,7 +42,7 @@ function panels_simple_cache_get_cache($conf, $display, $args, $contexts, $pane
*/
function panels_simple_cache_set_cache($conf, $content, $display, $args, $contexts, $pane = NULL) {
$cid = panels_simple_cache_get_id($conf, $display, $args, $contexts, $pane);
cache_set($cid, $content);
cache_set($cid, $content, 'cache_panels');
}
/**
@@ -53,13 +53,25 @@ function panels_simple_cache_set_cache($conf, $content, $display, $args, $contex
function panels_simple_cache_clear_cache($display) {
$cid = 'panels_simple_cache';
// This is used in case this is an in-code display, which means did will be something like 'new-1'.
if (isset($display->owner) && isset($display->owner->id)) {
$cid .= ':' . $display->owner->id;
// If the panel is stored in the database it'll have a numeric did value.
if (is_numeric($display->did)) {
$cid .= ':' . $display->did;
}
// Exported panels won't have a numeric did but may have a usable cache_key.
elseif (!empty($display->cache_key)) {
$cid .= ':' . str_replace('panel_context:', '', $display->cache_key);
}
// Alternatively use the css_id.
elseif (!empty($display->css_id)) {
$cid .= ':' . $display->css_id;
}
// Failover to just appending the did, which may be the completely unusable
// string 'new'.
else {
$cid .= ':' . $display->did;
}
$cid .= ':' . $display->did;
cache_clear_all($cid, 'cache', TRUE);
cache_clear_all($cid, 'cache_panels', TRUE);
}
/**

View File

@@ -61,6 +61,7 @@ class panels_renderer_editor extends panels_renderer_standard {
ctools_add_js('display_editor', 'panels');
ctools_add_css('panels_dnd', 'panels');
ctools_add_css('panels_admin', 'panels');
drupal_add_library('system', 'ui');
}
}
@@ -161,7 +162,7 @@ class panels_renderer_editor extends panels_renderer_standard {
if ($buttons) {
$output .= '<span class="buttons">' . $buttons . '</span>';
}
$output .= '<span class="text">' . $title . '</span>';
$output .= '<span class="text" title="' . check_plain($title) . '">' . $title . '</span>';
$output .= '</div>'; // grabber
$output .= '<div class="panel-pane-collapsible">';
@@ -186,12 +187,12 @@ class panels_renderer_editor extends panels_renderer_standard {
$style_title = isset($style['title']) ? $style['title'] : t('Default');
$style_links[] = array(
$style_links['title'] = array(
'title' => $style_title,
'attributes' => array('class' => array('panels-text')),
);
$style_links[] = array(
$style_links['change'] = array(
'title' => t('Change'),
'href' => $this->get_url('style-type', $type, $id),
'attributes' => array('class' => array('ctools-use-modal')),
@@ -199,7 +200,7 @@ class panels_renderer_editor extends panels_renderer_standard {
$function = $type != 'pane' ? 'settings form' : 'pane settings form';
if (panels_plugin_get_function('styles', $style, $function)) {
$style_links[] = array(
$style_links['settings'] = array(
'title' => t('Settings'),
'href' => $this->get_url('style-settings', $type, $id),
'attributes' => array('class' => array('ctools-use-modal')),
@@ -307,14 +308,14 @@ class panels_renderer_editor extends panels_renderer_standard {
$links = array();
if (!empty($pane->shown)) {
$links[] = array(
$links['top']['disabled'] = array(
'title' => t('Disable this pane'),
'href' => $this->get_url('hide', $pane->pid),
'attributes' => array('class' => array('use-ajax')),
);
}
else {
$links[] = array(
$links['top']['enable'] = array(
'title' => t('Enable this pane'),
'href' => $this->get_url('show', $pane->pid),
'attributes' => array('class' => array('use-ajax')),
@@ -322,13 +323,13 @@ class panels_renderer_editor extends panels_renderer_standard {
}
if (isset($this->display->title_pane) && $this->display->title_pane == $pane->pid) {
$links['panels-set-title'] = array(
$links['top']['panels-set-title'] = array(
'title' => t('&#x2713;Panel title'),
'html' => TRUE,
);
}
else {
$links['panels-set-title'] = array(
$links['top']['panels-set-title'] = array(
'title' => t('Panel title'),
'href' => $this->get_url('panel-title', $pane->pid),
'attributes' => array('class' => array('use-ajax')),
@@ -338,7 +339,7 @@ class panels_renderer_editor extends panels_renderer_standard {
$subtype = ctools_content_get_subtype($content_type, $pane->subtype);
if (ctools_content_editable($content_type, $subtype, $pane->configuration)) {
$links[] = array(
$links['top']['settings'] = array(
'title' => isset($content_type['edit text']) ? $content_type['edit text'] : t('Settings'),
'href' => $this->get_url('edit-pane', $pane->pid),
'attributes' => array('class' => array('ctools-use-modal')),
@@ -346,7 +347,7 @@ class panels_renderer_editor extends panels_renderer_standard {
}
if (user_access('administer advanced pane settings')) {
$links[] = array(
$links['top']['css'] = array(
'title' => t('CSS properties'),
'href' => $this->get_url('pane-css', $pane->pid),
'attributes' => array('class' => array('ctools-use-modal')),
@@ -354,26 +355,10 @@ class panels_renderer_editor extends panels_renderer_standard {
}
if (user_access('administer panels styles')) {
$links[] = array(
'title' => '<hr />',
'html' => TRUE,
);
$style_links = $this->get_style_links('pane', $pane->pid);
$links[] = array(
'title' => '<span class="dropdown-header">' . t('Style') . '</span>' . theme_links(array('links' => $style_links, 'attributes' => array(), 'heading' => array())),
'html' => TRUE,
'attributes' => array('class' => array('panels-sub-menu')),
);
$links['style'] = $this->get_style_links('pane', $pane->pid);
}
if (user_access('administer pane access')) {
$links[] = array(
'title' => '<hr />',
'html' => TRUE,
);
$contexts = $this->display->context;
// Make sure we have the logged in user context
if (!isset($contexts['logged-in-user'])) {
@@ -385,7 +370,7 @@ class panels_renderer_editor extends panels_renderer_standard {
if (!empty($pane->access['plugins'])) {
foreach ($pane->access['plugins'] as $id => $test) {
$plugin = ctools_get_access_plugin($test['name']);
$access_title = isset($plugin['title']) ? $plugin['title'] : t('Broken/missing access plugin %plugin', array('%plugin' => $test['name']));
$access_title = isset($plugin['title']) ? $plugin['title'] : t('Broken/missing access plugin %plugin', array('%plugin' => $test['name']));
$access_description = ctools_access_summary($plugin, $contexts, $test);
$visibility_links[] = array(
@@ -396,37 +381,28 @@ class panels_renderer_editor extends panels_renderer_standard {
}
}
if (empty($visibility_links)) {
$visibility_links[] = array(
$visibility_links['no_rules'] = array(
'title' => t('No rules'),
'attributes' => array('class' => array('panels-text')),
);
}
$visibility_links[] = array(
$visibility_links['add_rule'] = array(
'title' => t('Add new rule'),
'href' => $this->get_url('access-add-test', $pane->pid),
'attributes' => array('class' => array('ctools-use-modal')),
);
$visibility_links[] = array(
$visibility_links['settings'] = array(
'title' => t('Settings'),
'href' => $this->get_url('access-settings', $pane->pid),
'attributes' => array('class' => array('ctools-use-modal')),
);
$links[] = array(
'title' => '<span class="dropdown-header">' . t('Visibility rules') . '</span>' . theme_links(array('links' => $visibility_links, 'attributes' => array(), 'heading' => array())),
'html' => TRUE,
'attributes' => array('class' => array('panels-sub-menu')),
);
$links['visibility'] = $visibility_links;
}
if (user_access('use panels locks')) {
$links[] = array(
'title' => '<hr />',
'html' => TRUE,
);
$lock_type = !empty($pane->locks['type']) ? $pane->locks['type'] : 'none';
switch ($lock_type) {
case 'immovable':
@@ -441,62 +417,44 @@ class panels_renderer_editor extends panels_renderer_standard {
break;
}
$lock_links[] = array(
$lock_links['lock'] = array(
'title' => $lock_method,
'attributes' => array('class' => array('panels-text')),
);
$lock_links[] = array(
$lock_links['change'] = array(
'title' => t('Change'),
'href' => $this->get_url('lock', $pane->pid),
'attributes' => array('class' => array('ctools-use-modal')),
);
$links[] = array(
'title' => '<span class="dropdown-header">' . t('Locking') . '</span>' . theme_links(array('links' => $lock_links, 'attributes' => array(), 'heading' => array())),
'html' => TRUE,
'attributes' => array('class' => array('panels-sub-menu')),
);
$links['lock'] = $lock_links;
}
if (panels_get_caches() && user_access('use panels caching features')) {
$links[] = array(
'title' => '<hr />',
'html' => TRUE,
);
$method = isset($pane->cache['method']) ? $pane->cache['method'] : 0;
$info = panels_get_cache($method);
$cache_method = isset($info['title']) ? $info['title'] : t('No caching');
$cache_links[] = array(
$cache_links['title'] = array(
'title' => $cache_method,
'attributes' => array('class' => array('panels-text')),
);
$cache_links[] = array(
$cache_links['change'] = array(
'title' => t('Change'),
'href' => $this->get_url('cache-method', $pane->pid),
'attributes' => array('class' => array('ctools-use-modal')),
);
if (panels_plugin_get_function('cache', $info, 'settings form')) {
$cache_links[] = array(
$cache_links['settings'] = array(
'title' => t('Settings'),
'href' => $this->get_url('cache-settings', $pane->pid),
'attributes' => array('class' => array('ctools-use-modal')),
);
}
$links[] = array(
'title' => '<span class="dropdown-header">' . t('Caching') . '</span>' . theme_links(array('links' => $cache_links, 'attributes' => array(), 'heading' => array())),
'html' => TRUE,
'attributes' => array('class' => array('panels-sub-menu')),
);
$links['cache'] = $cache_links;
}
$links[] = array(
'title' => '<hr />',
'html' => TRUE,
);
$links[] = array(
$links['bottom']['remove'] = array(
'title' => t('Remove'),
'href' => '#',
'attributes' => array(
@@ -505,7 +463,38 @@ class panels_renderer_editor extends panels_renderer_standard {
),
);
return theme('ctools_dropdown', array('title' => theme('image', array('path' => ctools_image_path('icon-configure.png', 'panels'))), 'links' => $links, 'image' => TRUE));
// Allow others to add/remove links from pane context menu.
// Grouped by 'top', 'style', 'visibility', 'lock', 'cache' and 'bottom'
drupal_alter('get_pane_links', $links, $pane, $content_type);
$dropdown_links = $links['top'];
$category_labels = array(
'style' => 'Style',
'visibility' => 'Visibility rules',
'lock' => 'Locking',
'cache' => 'Caching',
);
foreach ($category_labels as $category => $label) {
if (array_key_exists($category, $links)) {
$dropdown_links[] = array(
'title' => '<hr />',
'html' => TRUE,
);
$dropdown_links[] = array(
'title' => '<span class="dropdown-header">' . t($label) . '</span>' . theme_links(array('links' => $links[$category], 'attributes' => array(), 'heading' => array())),
'html' => TRUE,
'attributes' => array('class' => array('panels-sub-menu')),
);
}
}
$dropdown_links[] = array(
'title' => '<hr />',
'html' => TRUE,
);
$dropdown_links = array_merge($dropdown_links, $links['bottom']);
return theme('ctools_dropdown', array('title' => theme('image', array('path' => ctools_image_path('icon-configure.png', 'panels'))), 'links' => $dropdown_links, 'image' => TRUE));
}
// -----------------------------------------------------------------------
@@ -525,6 +514,40 @@ class panels_renderer_editor extends panels_renderer_standard {
return $url;
}
/**
* Get the Panels storage oparation for a given renderer AJAX method.
*
* @param string $method
* The method name.
*
* @return string
* The Panels storage op.
*/
function get_panels_storage_op_for_ajax($method) {
switch ($method) {
case 'ajax_show':
case 'ajax_hide':
case 'ajax_select_content':
case 'ajax_add_pane':
case 'ajax_edit_pane':
case 'ajax_panel_title':
case 'ajax_cache_method':
case 'ajax_cache_settings':
case 'ajax_style_type':
case 'ajax_style_settings':
case 'ajax_pane_css':
case 'ajax_lock':
case 'ajax_access_settings':
case 'ajax_access_add_test':
case 'ajax_access_configure_test':
case 'ajax_layout':
case 'ajax_style':
return 'update';
}
return parent::get_panels_storage_op_for_ajax($method);
}
/**
* AJAX command to show a pane.
*/
@@ -572,6 +595,11 @@ class panels_renderer_editor extends panels_renderer_standard {
$output = theme('panels_add_content_modal', array('renderer' => $this, 'categories' => $categories, 'category' => $category, 'region' => $region));
}
$this->commands[] = ctools_modal_command_display($title, $output);
// Give keybord focus to the first item in the category we just loaded.
if (!empty($category)) {
$this->commands[] = ajax_command_invoke(".panels-add-content-modal .panels-section-columns :focusable:first", 'focus');
}
}
/**
@@ -656,7 +684,19 @@ class panels_renderer_editor extends panels_renderer_standard {
$content_type = ctools_get_content_type($type_name);
$subtype = ctools_content_get_subtype($content_type, $subtype_name);
if (!isset($step) || !isset($this->cache->new_pane)) {
// Determine if we are adding a different pane than previously cached. This
// is used to load the different pane into cache so that multistep forms
// have the correct context instead of a previously cached version that
// does not match the pane currently being added.
$is_different_pane = FALSE;
if (isset($this->cache) && isset($this->cache->new_pane)) {
$diff_type = $type_name != $this->cache->new_pane->type;
$diff_subtype = $subtype_name != $this->cache->new_pane->subtype;
$is_different_pane = $diff_type || $diff_subtype;
}
if (!isset($step) || !isset($this->cache->new_pane) || $is_different_pane) {
$pane = panels_new_pane($type_name, $subtype_name, TRUE);
$this->cache->new_pane = &$pane;
}
@@ -947,8 +987,11 @@ class panels_renderer_editor extends panels_renderer_standard {
ctools_include('content');
$pane = &$this->display->content[$pid];
$style = isset($pane->style['style']) ? $pane->style['style'] : 'default';
$subtype = ctools_content_get_subtype($pane->type, $pane->subtype);
$title = t('Pane style for "!pane"', array('!pane' => $subtype['title']));
$title = ctools_content_admin_title($pane->type, $pane->subtype, $pane->configuration, $this->display->context);
if (!$title) {
$title = $pane->type;
}
$title = t('Pane style for "!title"', array('!title' => $title));
break;
default:
@@ -1163,9 +1206,21 @@ class panels_renderer_editor extends panels_renderer_standard {
unset($this->cache->style);
}
if (!empty($form_state['cancel'])) {
// The cache must be saved prior to dismissing the modal.
panels_edit_cache_set($this->cache);
$this->commands[] = ctools_modal_command_dismiss();
return;
}
// Copy settings from form state back into the cache.
if(!empty($form_state['values']['settings'])) {
$this->cache->display->content[$pid]->style['settings'] = $form_state['values']['settings'];
if ($type == 'pane') {
$this->cache->display->content[$pid]->style['settings'] = $form_state['values']['settings'];
}
else if($type == 'region') {
$this->cache->display->panel_settings['style_settings'][$pid] = $form_state['values']['settings'];
}
}
panels_edit_cache_set($this->cache);
@@ -1485,7 +1540,7 @@ function panels_ajax_edit_pane_next(&$form_state) {
}
/**
* Handle the 'finish' click on teh add/edit pane form wizard.
* Handle the 'finish' click on the add/edit pane form wizard.
*
* All we need to do is set a flag so the return can handle adding
* the pane.
@@ -1510,6 +1565,8 @@ function panels_ajax_edit_pane_cancel(&$form_state) {
* Choose cache method form
*/
function panels_edit_cache_method_form($form, &$form_state) {
ctools_form_include($form_state, 'plugins', 'panels');
form_load_include($form_state, 'php', 'panels', '/plugins/display_renderers/panels_renderer_editor.class');
$display = &$form_state['display'];
$conf = &$form_state['conf'];
@@ -1558,6 +1615,8 @@ function panels_edit_cache_method_form_submit($form, &$form_state) {
* Cache settings form
*/
function panels_edit_cache_settings_form($form, &$form_state) {
ctools_form_include($form_state, 'plugins', 'panels');
form_load_include($form_state, 'php', 'panels', '/plugins/display_renderers/panels_renderer_editor.class');
$display = &$form_state['display'];
$conf = &$form_state['conf'];
$pid = $form_state['pid'];
@@ -1618,6 +1677,8 @@ function panels_edit_cache_settings_form_submit($form, &$form_state) {
* Choose style form
*/
function panels_edit_style_type_form($form, &$form_state) {
ctools_form_include($form_state, 'plugins', 'panels');
form_load_include($form_state, 'php', 'panels', '/plugins/display_renderers/panels_renderer_editor.class');
$display = &$form_state['display'];
$style = $form_state['style'];
$type = $form_state['type'];
@@ -1668,6 +1729,8 @@ function panels_edit_style_type_form_submit($form, &$form_state) {
* Style settings form
*/
function panels_edit_style_settings_form($form, &$form_state) {
ctools_form_include($form_state, 'plugins', 'panels');
form_load_include($form_state, 'php', 'panels', '/plugins/display_renderers/panels_renderer_editor.class');
$display = &$form_state['display'];
$conf = &$form_state['conf'];
$pid = $form_state['pid'];
@@ -1692,9 +1755,28 @@ function panels_edit_style_settings_form($form, &$form_state) {
'#value' => t('Save'),
);
// Need a cancel button since the style cache can persist and impact the wrong
// pane (or region, or display).
$form['cancel_style'] = array(
'#type' => 'submit',
'#value' => t('Cancel'),
'#submit' => array('panels_edit_style_settings_form_cancel'),
);
return $form;
}
/**
* Cancel style settings form.
*
* Clears the editing cache to prevent styles being applied to incorrect regions
* or panes.
*/
function panels_edit_style_settings_form_cancel($form, &$form_state) {
$form_state['cancel'] = TRUE;
}
/**
* Validate style settings.
*/
@@ -1722,6 +1804,8 @@ function panels_edit_style_settings_form_submit($form, &$form_state) {
* Configure CSS on a pane form.
*/
function panels_edit_configure_pane_css_form($form, &$form_state) {
ctools_form_include($form_state, 'plugins', 'panels');
form_load_include($form_state, 'php', 'panels', '/plugins/display_renderers/panels_renderer_editor.class');
$display = &$form_state['display'];
$pane = &$form_state['pane'];
@@ -1729,13 +1813,13 @@ function panels_edit_configure_pane_css_form($form, &$form_state) {
'#type' => 'textfield',
'#default_value' => isset($pane->css['css_id']) ? $pane->css['css_id'] : '',
'#title' => t('CSS ID'),
'#description' => t('CSS ID to apply to this pane. This may be blank.'),
'#description' => t('CSS ID to apply to this pane. This may be blank. Keywords from context are allowed.'),
);
$form['css_class'] = array(
'#type' => 'textfield',
'#default_value' => isset($pane->css['css_class']) ? $pane->css['css_class'] : '',
'#title' => t('CSS class'),
'#description' => t('CSS class to apply to this pane. This may be blank.'),
'#description' => t('CSS class to apply to this pane. This may be blank. Keywords from context are allowed.'),
);
$form['next'] = array(
@@ -1764,6 +1848,8 @@ function panels_edit_configure_pane_css_form_submit($form, &$form_state) {
* Configure lock on a pane form.
*/
function panels_edit_configure_pane_lock_form($form, &$form_state) {
ctools_form_include($form_state, 'plugins', 'panels');
form_load_include($form_state, 'php', 'panels', '/plugins/display_renderers/panels_renderer_editor.class');
$display = &$form_state['display'];
$pane = &$form_state['pane'];
@@ -1839,6 +1925,8 @@ function panels_edit_configure_pane_lock_form_submit($form, &$form_state) {
* Form to control basic visibility settings.
*/
function panels_edit_configure_access_settings_form($form, &$form_state) {
ctools_form_include($form_state, 'plugins', 'panels');
form_load_include($form_state, 'php', 'panels', '/plugins/display_renderers/panels_renderer_editor.class');
$display = &$form_state['display'];
$pane = &$form_state['pane'];
@@ -1876,6 +1964,8 @@ function panels_edit_configure_access_settings_form_submit($form, &$form_state)
* Form to add a visibility rule.
*/
function panels_edit_add_access_test_form($form, &$form_state) {
ctools_form_include($form_state, 'plugins', 'panels');
form_load_include($form_state, 'php', 'panels', '/plugins/display_renderers/panels_renderer_editor.class');
$display = &$form_state['display'];
$pane = &$form_state['pane'];
@@ -1905,6 +1995,8 @@ function panels_edit_add_access_test_form($form, &$form_state) {
* Form to configure a visibility rule.
*/
function panels_edit_configure_access_test_form($form, &$form_state) {
ctools_form_include($form_state, 'plugins', 'panels');
form_load_include($form_state, 'php', 'panels', '/plugins/display_renderers/panels_renderer_editor.class');
$display = &$form_state['display'];
$test = &$form_state['test'];
$plugin = &$form_state['plugin'];

View File

@@ -151,6 +151,15 @@ class panels_renderer_standard {
*/
var $suffix = '';
/**
* Boolean flag indicating whether to render the layout even if all rendered
* regions are blank. If FALSE, the layout renders as an empty string (without
* prefix or suffix) if not in administrative mode.
*
* @var bool
*/
var $show_empty_layout = TRUE;
/**
* Receive and store the display object to be rendered.
*
@@ -176,6 +185,19 @@ class panels_renderer_standard {
}
}
/**
* Get the Panels storage oparation for a given renderer AJAX method.
*
* @param string $method
* The method name.
*
* @return string
* The Panels storage op.
*/
function get_panels_storage_op_for_ajax($method) {
return 'read';
}
/**
* Prepare the attached display for rendering.
*
@@ -396,6 +418,22 @@ class panels_renderer_standard {
$theme = $this->plugins['layout']['theme'];
}
// Determine whether to render layout.
$show = TRUE;
if (!$this->show_empty_layout && !$this->admin) {
$show = FALSE;
// Render layout if any region is not empty.
foreach ($this->rendered['regions'] as $region) {
if (is_string($region) && $region !== '') {
$show = TRUE;
break;
}
}
}
if (!$show) {
return;
}
$this->rendered['layout'] = theme($theme, array('css_id' => check_plain($this->display->css_id), 'content' => $this->rendered['regions'], 'settings' => $this->display->layout_settings, 'display' => $this->display, 'layout' => $this->plugins['layout'], 'renderer' => $this));
return $this->prefix . $this->rendered['layout'] . $this->suffix;
}
@@ -407,17 +445,38 @@ class panels_renderer_standard {
* their CSS added in the right order: inner content before outer content.
*/
function add_meta() {
global $theme;
if (!empty($this->plugins['layout']['css'])) {
if (file_exists(path_to_theme() . '/' . $this->plugins['layout']['css'])) {
$this->add_css(path_to_theme() . '/' . $this->plugins['layout']['css']);
// Do not use the path_to_theme() function, because it returns the
// $GLOBALS['theme_path'] value, which may be overriden in the theme()
// function when the theme hook defines the key 'theme path'.
$theme_path = isset($theme) ? drupal_get_path('theme', $theme) : '';
$css = $this->plugins['layout']['css'];
if (!is_array($css)) {
$css = array($css);
}
else {
$this->add_css($this->plugins['layout']['path'] . '/' . $this->plugins['layout']['css']);
// Load each of the CSS files defined in this layout.
foreach ($css as $file) {
if (!empty($theme_path) && file_exists($theme_path . '/' . $file)) {
$this->add_css($theme_path . '/' . $file);
}
else {
$this->add_css($this->plugins['layout']['path'] . '/' . $file);
}
}
}
if ($this->admin && isset($this->plugins['layout']['admin css'])) {
$this->add_css($this->plugins['layout']['path'] . '/' . $this->plugins['layout']['admin css']);
$admin_css = $this->plugins['layout']['admin css'];
if (!is_array($admin_css)) {
$admin_css = array($admin_css);
}
foreach ($admin_css as $file) {
$this->add_css($this->plugins['layout']['path'] . '/' . $file);
}
}
}
@@ -453,6 +512,7 @@ class panels_renderer_standard {
* The array of rendered panes, keyed on pane pid.
*/
function render_panes() {
drupal_alter('panels_prerender_panes', $this);
ctools_include('content');
// First, render all the panes into little boxes.
@@ -477,6 +537,8 @@ class panels_renderer_standard {
* A Panels pane object, as loaded from the database.
*/
function render_pane(&$pane) {
module_invoke_all('panels_pane_prerender', $pane);
$content = $this->render_pane_content($pane);
if ($this->display->hide_title == PANELS_TITLE_PANE && !empty($this->display->title_pane) && $this->display->title_pane == $pane->pid) {
@@ -530,7 +592,6 @@ class panels_renderer_standard {
$this->display->context = array();
}
$content = FALSE;
$caching = !empty($pane->cache['method']) && empty($this->display->skip_cache);
if ($caching && ($cache = panels_get_cached_content($this->display, $this->display->args, $this->display->context, $pane))) {
$content = $cache->content;
@@ -544,10 +605,6 @@ class panels_renderer_standard {
$content = ctools_content_render($pane->type, $pane->subtype, $pane->configuration, array(), $this->display->args, $this->display->context);
if (empty($content)) {
return;
}
foreach (module_implements('panels_pane_content_alter') as $module) {
$function = $module . '_panels_pane_content_alter';
$function($content, $pane, $this->display->args, $this->display->context, $this, $this->display);
@@ -559,14 +616,19 @@ class panels_renderer_standard {
}
}
// Pass long the css_id that is usually available.
if (!empty($pane->css['css_id'])) {
$content->css_id = check_plain($pane->css['css_id']);
}
// If there's content, check if we've css configuration to add.
if (!empty($content)) {
// Pass long the css_id that is usually available.
if (!empty($pane->css['css_id'])) {
$id = ctools_context_keyword_substitute($pane->css['css_id'], array(), $this->display->context);
$content->css_id = check_plain($id);
}
// Pass long the css_class that is usually available.
if (!empty($pane->css['css_class'])) {
$content->css_class = check_plain($pane->css['css_class']);
// Pass long the css_class that is usually available.
if (!empty($pane->css['css_class'])) {
$class = ctools_context_keyword_substitute($pane->css['css_class'], array(), $this->display->context, array('css safe' => TRUE));
$content->css_class = check_plain($class);
}
}
return $content;
@@ -580,6 +642,7 @@ class panels_renderer_standard {
* An array of rendered panel regions, keyed on the region name.
*/
function render_regions() {
drupal_alter('panels_prerender_regions', $this);
$this->rendered['regions'] = array();
// Loop through all panel regions, put all panes that belong to the current

View File

@@ -17,7 +17,7 @@ Drupal.flexible.fixHeight = function() {
Drupal.behaviors.flexibleAdmin = {
attach: function(context) {
// Show/hide layout manager button
$('input#panels-flexible-toggle-layout:not(.panels-flexible-processed)', context)
$('#panels-flexible-toggle-layout:not(.panels-flexible-processed)', context)
.addClass('panels-flexible-processed')
.click(function() {
$('.panel-flexible-admin')
@@ -290,9 +290,6 @@ Drupal.flexible.splitter = function($splitter) {
// if not moving the right side, adjust the parent padding instead.
splitter.parent.css('padding-left', (splitter.left_padding - moved) + 'px');
splitter.left.parent().css('margin-left', (splitter.left_parent + moved) + 'px');
if (jQuery.browser.msie) {
splitter.left.parent().css('left', splitter.currentLeft);
}
}
return false;
};

View File

@@ -471,15 +471,26 @@ function panels_flexible_render_items($renderer, $list, $owner_id) {
switch ($item['type']) {
case 'column':
$content = panels_flexible_render_items($renderer, $item['children'], $renderer->base['column'] . '-' . $id);
$groups[$location] .= panels_flexible_render_item($renderer, $item, $content, $id, $position, $max);
if (empty($renderer->settings['items'][$id]['hide_empty']) || trim($content)) {
$groups[$location] .= panels_flexible_render_item($renderer, $item, $content, $id, $position, $max);
}
break;
case 'row':
$content = panels_flexible_render_items($renderer, $item['children'], $renderer->base['row'] . '-' . $id);
$groups[$location] .= panels_flexible_render_item($renderer, $item, $content, $id, $position, $max, TRUE);
if (empty($renderer->settings['items'][$id]['hide_empty']) || trim($content)) {
$groups[$location] .= panels_flexible_render_item($renderer, $item, $content, $id, $position, $max, TRUE);
}
break;
case 'region':
$content = isset($renderer->content[$id]) ? $renderer->content[$id] : "&nbsp;";
$groups[$location] .= panels_flexible_render_item($renderer, $item, $content, $id, $position, $max);
if (empty($renderer->settings['items'][$id]['hide_empty'])) {
$content = isset($renderer->content[$id]) ? $renderer->content[$id] : "&nbsp;";
}
else {
$content = isset($renderer->content[$id]) ? trim($renderer->content[$id]) : "";
}
if (empty($renderer->settings['items'][$id]['hide_empty']) || $content) {
$groups[$location] .= panels_flexible_render_item($renderer, $item, $content, $id, $position, $max);
}
break;
}
@@ -1186,6 +1197,12 @@ function panels_flexible_config_item_form($form, &$form_state) {
}
}
$form['hide_empty'] = array(
'#title' => t('Hide element if empty'),
'#type' => 'checkbox',
'#default_value' => !empty($item['hide_empty']) ? 1 : 0,
);
$form['save'] = array(
'#type' => 'submit',
'#value' => t('Save'),
@@ -1223,6 +1240,7 @@ function panels_flexible_config_item_form_submit(&$form, &$form_state) {
else {
$item['contains'] = $form_state['values']['contains'];
}
$item['hide_empty'] = $form_state['values']['hide_empty'];
}
@@ -1486,6 +1504,12 @@ function panels_flexible_add_item_form($form, &$form_state) {
);
}
$form['hide_empty'] = array(
'#title' => t('Hide element if empty'),
'#type' => 'checkbox',
'#default_value' => 0,
);
$form['save'] = array(
'#type' => 'submit',
'#value' => t('Save'),
@@ -1516,6 +1540,8 @@ function panels_flexible_add_item_form_submit(&$form, &$form_state) {
$item['contains'] = $form_state['values']['contains'];
}
$item['hide_empty'] = $form_state['values']['hide_empty'];
if ($item['type'] == 'region') {
// derive the region key from the title
$key = preg_replace("/[^a-z0-9]/", '_', drupal_strtolower($item['title']));

View File

@@ -18,7 +18,7 @@
width: 25%;
}
.panel-3col-stacked .panel-col .inside {
.panel-3col-stacked .panel-col-first .inside {
margin: 0 .5em 1em .5em;
}

View File

@@ -66,6 +66,8 @@ function panels_landing_page_new_page(&$cache) {
);
$cache->display = panels_new_display();
$cache->display->layout = 'flexible';
$cache->display->storage_type = 'page_manager';
$cache->display->storage_id = 'new';
}
/**
@@ -257,6 +259,9 @@ function panels_landing_page_finish(&$form_state) {
// Create the the panel context variant configured with our display
$plugin = page_manager_get_task_handler('panel_context');
// Set the storage id.
$cache->display->storage_id = $cache->name;
// Create a new handler.
$handler = page_manager_new_task_handler($plugin);
$handler->conf['title'] = t('Landing page');

View File

@@ -0,0 +1,19 @@
<?php
/**
* @file
* Provides a panels_storage plugin for page_manager.
*/
// Plugin definition
$plugin = array(
'access callback' => 'page_manager_panels_storage_access',
);
/**
* Access callback for panels storage.
*/
function page_manager_panels_storage_access($storage_type, $storage_id, $op, $account) {
// Only users with the 'use page manager' or administer page manager perms.
return user_access('use page manager', $account) || user_access('administer page manager', $account) || user_access('use ipe with page manager', $account);
}

View File

@@ -286,7 +286,8 @@ function panels_panel_context_render($handler, $base_contexts, $args, $test = TR
$display->context = $contexts;
$display->args = $args;
$display->css_id = $handler->conf['css_id'];
$page_css_id = ctools_context_keyword_substitute($handler->conf['css_id'], array(), $contexts);
$display->css_id = check_plain($page_css_id);
$task_name = page_manager_make_task_name($handler->task, $handler->subtask);
$display->cache_key = panels_panel_context_cache_key($task_name, $handler->name, $args);
@@ -297,7 +298,9 @@ function panels_panel_context_render($handler, $base_contexts, $args, $test = TR
$css_id = 'panel_context:' . $handler->name;
$filename = ctools_css_retrieve($css_id);
if (!$filename) {
$filename = ctools_css_store($css_id, $handler->conf['css']);
// Add keywords from context
$css = ctools_context_keyword_substitute($handler->conf['css'], array(), $contexts, array('css safe' => TRUE));
$filename = ctools_css_store($css_id, $css);
}
drupal_add_css($filename);
}
@@ -317,11 +320,23 @@ function panels_panel_context_render($handler, $base_contexts, $args, $test = TR
// Remove and add body element classes
$panel_body_css = &drupal_static('panel_body_css');
if (isset($handler->conf['body_classes_to_remove']) && !isset($panel_body_css['body_classes_to_remove'])) {
$panel_body_css['body_classes_to_remove'] = $handler->conf['body_classes_to_remove'];
if (isset($handler->conf['body_classes_to_remove'])) {
$classes = ctools_context_keyword_substitute($handler->conf['body_classes_to_remove'], array(), $contexts, array('css safe' => TRUE));
if (!isset($panel_body_css['body_classes_to_remove'])) {
$panel_body_css['body_classes_to_remove'] = check_plain($classes);
}
else{
$panel_body_css['body_classes_to_remove'] .= ' ' . check_plain($classes);
}
}
if (isset($handler->conf['body_classes_to_add']) && !isset($panel_body_css['body_classes_to_add'])) {
$panel_body_css['body_classes_to_add'] = $handler->conf['body_classes_to_add'];
if (isset($handler->conf['body_classes_to_add'])) {
$classes = ctools_context_keyword_substitute($handler->conf['body_classes_to_add'], array(), $contexts, array('css safe' => TRUE));
if (!isset($panel_body_css['body_classes_to_add'])) {
$panel_body_css['body_classes_to_add'] = check_plain($classes);
}
else {
$panel_body_css['body_classes_to_add'] .= ' '. check_plain($classes);
}
}
$info = array(
@@ -393,7 +408,10 @@ function panels_panel_context_export(&$handler, $indent) {
unset($handler->conf[$item]);
}
}
$display->did = 'new';
$display = (object) array(
'did' => 'new',
'uuid' => ctools_uuid_generate(),
);
$handler->conf['display'] = $display;
}
@@ -568,6 +586,19 @@ function panels_panel_context_edit_choose($form, &$form_state) {
$form_state['display'] = &panels_panel_context_get_display($form_state['handler']);
// Grab the storage_type and storage_id and inject it into the display.
if (empty($form_state['display']->storage_type)) {
if (!isset($form_state[$form_state['task_id']]->storage_type)) {
watchdog('panels', "Unable to find the storage type for specified storage. Read 'Upgrading task handlers' in CHANGELOG.txt", array(), WATCHDOG_ERROR);
$form_state['display']->storage_type = 'unknown';
}
else {
$form_state['display']->storage_type = $form_state[$form_state['task_id']]->storage_type;
}
// When adding variants, we don't know the handler id yet. In that case,
// Mark it as new. We'll assign it later.
$form_state['display']->storage_id = !empty($form_state['handler_id']) ? $form_state['handler_id'] : 'new';
}
// Tell the Panels form not to display buttons.
$form_state['no buttons'] = TRUE;
@@ -725,6 +756,10 @@ function panels_panel_context_edit_content_validate(&$form, &$form_state) {
}
function panels_panel_context_edit_content_submit(&$form, &$form_state) {
// Update the storage_id if this is a new variant before saving.
if ($form_state['display']->storage_id == 'new') {
$form_state['display']->storage_id = $form_state['handler_id'];
}
panels_edit_display_form_submit($form, $form_state);
$handler = &$form_state['handler'];
@@ -760,17 +795,17 @@ function panels_panel_context_edit_settings($form, &$form_state) {
$form['conf']['body_classes_to_remove'] = array(
'#type' => 'textfield',
'#size' => 128,
'#default_value' => $conf['body_classes_to_remove'],
'#default_value' => empty($conf['body_classes_to_remove']) ? '' : $conf['body_classes_to_remove'],
'#title' => t('Remove body CSS classes'),
'#description' => t('The CSS classes to remove from the body element of this page. Separated by a space. For example: no-sidebars one-sidebar sidebar-first sidebar-second two-sidebars.'),
'#description' => t('The CSS classes to remove from the body element of this page. Separated by a space. For example: no-sidebars one-sidebar sidebar-first sidebar-second two-sidebars. Keywords from context are allowed.'),
);
$form['conf']['body_classes_to_add'] = array(
'#type' => 'textfield',
'#size' => 128,
'#default_value' => $conf['body_classes_to_add'],
'#default_value' => empty($conf['body_classes_to_add']) ? '' : $conf['body_classes_to_add'],
'#title' => t('Add body CSS classes'),
'#description' => t('The CSS classes to add to the body element of this page. Separated by a space. For example: no-sidebars one-sidebar sidebar-first sidebar-second two-sidebars.'),
'#description' => t('The CSS classes to add to the body element of this page. Separated by a space. For example: no-sidebars one-sidebar sidebar-first sidebar-second two-sidebars. Keywords from context are allowed.'),
);
ctools_include('plugins', 'panels');
@@ -810,13 +845,13 @@ function panels_panel_context_edit_settings($form, &$form_state) {
'#size' => 35,
'#default_value' => $conf['css_id'],
'#title' => t('CSS ID'),
'#description' => t('The CSS ID to apply to this page'),
'#description' => t('The CSS ID to apply to this page. Keywords from context are allowed.'),
);
$form['conf']['css'] = array(
'#type' => 'textarea',
'#title' => t('CSS code'),
'#description' => t('Enter well-formed CSS code here; this code will be embedded into the page, and should only be used for minor adjustments; it is usually better to try to put CSS for the page into the theme if possible. This CSS will be filtered for safety so some CSS may not work.'),
'#description' => t('Enter well-formed CSS code here; this code will be embedded into the page, and should only be used for minor adjustments; it is usually better to try to put CSS for the page into the theme if possible. This CSS will be filtered for safety so some CSS may not work. Keywords from context are allowed.'),
'#default_value' => $conf['css'],
);
@@ -900,12 +935,25 @@ function panels_panel_context_get_addressable($task, $subtask_name, $handler, $a
$display->cache_key = panels_panel_context_cache_key($task->name, $handler->name, $arguments);
$renderer = panels_get_renderer($handler->conf['pipeline'], $display);
if ($type == 'content') {
$renderer->prepare();
$renderer->prepare();
if ($address) {
$pid = array_shift($address);
if (!empty($renderer->prepared['panes'][$pid])) {
return $renderer->render_pane($renderer->prepared['panes'][$pid]);
if ($type == 'content') {
return $renderer->render_pane($renderer->prepared['panes'][$pid]);
}
elseif ($type == 'pane') {
return $renderer->prepared['panes'][$pid];
}
}
}
else {
if ($type == 'content') {
return $renderer->render();
}
elseif ($type == 'renderer') {
return $renderer;
}
}
}

View File

@@ -137,8 +137,8 @@ class panels_views_plugin_row_fields extends views_plugin_row_fields {
// Now that we have distributed our fields, go through the regions and
// render them into the content array.
foreach ($this->region_fields as $region_id => $fields) {
$this->view->field = $fields;
foreach ($this->region_fields as $region_id => $fields_list) {
$this->view->field = $fields_list;
$content[$region_id] = theme($this->theme_functions(), array('view' => $this->view, 'options' => $this->options, 'row' => $row));
}

View File

@@ -5,6 +5,10 @@
*/
?>
<div class="content-type-button clearfix">
<?php print $image_button; ?>
<div><?php print $text_button; ?></div>
<?php if (isset($icon_text_button)): ?>
<?php print $icon_text_button; ?>
<?php else: ?>
<?php print $image_button; ?>
<div><?php print $text_button; ?></div>
<?php endif; ?>
</div>

View File

@@ -26,6 +26,12 @@
<?php if (!empty($columns)): ?>
<div class="panels-section-columns">
<div class="panels-section-columns-quickfilter container-inline">
<label for="quick-filter"><?php print t('Quick-Filter'); ?> </label> <input type="text" name="quickfilter" class="form-text" />
<script type="text/javascript">
(function ($) { Drupal.Panels.AddContentModalQuickFilter(); })(jQuery);
</script>
</div>
<?php foreach ($columns as $column_id => $column): ?>
<div class="panels-section-column panels-section-column-<?php print $column_id; ?> ">
<div class="inside">

View File

@@ -20,14 +20,16 @@
<?php if ($pane_prefix): ?>
<?php print $pane_prefix; ?>
<?php endif; ?>
<div class="<?php print $classes; ?>" <?php print $id; ?>>
<div class="<?php print $classes; ?>" <?php print $id; ?> <?php print $attributes; ?>>
<?php if ($admin_links): ?>
<?php print $admin_links; ?>
<?php endif; ?>
<?php print render($title_prefix); ?>
<?php if ($title): ?>
<h2<?php print $title_attributes; ?>><?php print $title; ?></h2>
<<?php print $title_heading; ?><?php print $title_attributes; ?>>
<?php print $title; ?>
</<?php print $title_heading; ?>>
<?php endif; ?>
<?php print render($title_suffix); ?>