From a0fadb0757d3f63c5e34e7aa44f865d46dd6b206 Mon Sep 17 00:00:00 2001
From: Bachir Soussi Chiadmi
' . t('Users with the "clone node" permission can utilize this functionality. A new tab will appear on node pages with the word "Clone".') . '
'; + return $output; + case 'node/%/clone': + $method = variable_get('clone_method', 'prepopulate'); + if ($method == 'prepopulate') { + return t('This clone will not be saved to the database until you submit.'); + } + } +} + +/** + * Implementation of hook_permission(). + */ +function clone_permission() { + return array( + 'clone node' => array('title' => t('Clone any node')), + 'clone own nodes' => array('title' => t('Clone own nodes.')), + ); +} + +/** + * Implementation of hook_menu(). + */ +function clone_menu() { + $items['admin/config/content/clone'] = array( + 'access arguments' => array('administer site configuration'), + 'page callback' => 'drupal_get_form', + 'page arguments' => array('clone_settings'), + 'title' => 'Node clone module', + 'file' => 'clone.pages.inc', + 'description' => 'Allows users to clone (copy then edit) an existing node.', + ); + $items['node/%node/clone/%clone_token'] = array( + 'access callback' => 'clone_access_cloning', + 'access arguments' => array(1, TRUE, 3), + 'page callback' => 'clone_node_check', + 'page arguments' => array(1), + 'title' => 'Clone content', + 'title callback' => 'clone_action_link_title', + 'title arguments' => array(1), + 'weight' => 5, + 'file' => 'clone.pages.inc', + 'type' => MENU_LOCAL_ACTION, + 'context' => MENU_CONTEXT_PAGE | MENU_CONTEXT_INLINE, + ); + return $items; +} + +/** + * Implements a to_arg function for the clone local action. + * + * @param string $arg + * The current argument value. + * @param array $map + * The path arguments. + * + * @return string + * Either 'confirm' or a CSRF token. + */ +function clone_token_to_arg($arg, $map) { + // Supply CSRF token if needed. + return clone_get_token($map[1]); +} + +/** + * Get the token that needs to be added to the clone link. + * + * @param int $nid + * The node ID of the node to be cloned + * + * @return string + * Either 'confirm' or a CSRF token. + */ +function clone_get_token($nid) { + if (variable_get('clone_nodes_without_confirm', FALSE) && variable_get('clone_method', 'prepopulate') != 'prepopulate') { + return drupal_get_token('clone_access_cloning-' . $nid); + } + return 'confirm'; +} + +function clone_access_cloning($node, $check_token = FALSE, $token = FALSE) { + global $user; + // Check CSRF token if needed. + if ($check_token) { + if (!$token || $token !== clone_get_token($node->nid)) { + return FALSE; + } + } + // Check basic permissions first. + $access = clone_is_permitted($node->type) && (user_access('clone node') || ($user->uid && ($node->uid == $user->uid) && user_access('clone own nodes'))); + // Make sure the user can view the original node content, and create a new one.. + $access = $access && node_access('view', $node) && node_access('create', $node->type); + // Let other modules alter this. + drupal_alter("clone_access", $access, $node); + return $access; +} + +function clone_is_permitted($type) { + $omitted = variable_get('clone_omitted', array()); + return empty($omitted[$type]); +} + +/** + * Menu title callback. + */ +function clone_action_link_title($node) { + // A hack to present a shorter title in contextual links. + if (current_path() != 'node/' . $node->nid) { + return t('Clone'); + } + if (variable_get('clone_use_node_type_name', 0)) { + return t('Clone this !type', array('!type' => drupal_strtolower(node_type_get_name($node)))); + } + return t('Clone content'); +} + +/** + * Implements hook_menu_local_tasks_alter + */ +function clone_menu_local_tasks_alter(&$data, $router_item, $root_path) { + // Remove tabs from the node clone form - these are confusing as they link to + // the the original node and its edit form. + if ($router_item['path'] == 'node/%/clone/%') { + $data['tabs'] = array(); + } +} + +/** + * Implementation of hook_node_type_delete(). + */ +function clone_node_type_delete($info) { + variable_del('clone_reset_' . $info->type); +} + +/** + * Implementation of hook_node_type_update(). + */ +function clone_node_type_update($info) { + if (!empty($info->old_type) && $info->old_type != $info->type) { + if (variable_get('clone_reset_' . $info->old_type, FALSE)) { + variable_del('clone_reset_' . $info->old_type); + variable_set('clone_reset_' . $info->type, TRUE); + } + } +} + +/** + * Implements hook_views_api. + */ +function clone_views_api() { + return array( + 'api' => 3, + 'path' => drupal_get_path('module', 'clone') . '/views', + ); +} + +/** + * Implementation of hook_admin_paths(). + */ +function clone_admin_paths() { + if (variable_get('node_admin_theme')) { + $paths = array( + 'node/*/clone/*' => TRUE, + ); + return $paths; + } +} + +/** + * Implements hook_form_BASE_FORM_ID_alter(). + */ +function clone_form_node_form_alter(&$form, $form_state, $form_id) { + // Add the clone_from_original_nid value for node forms triggered by cloning. + // This will make sure the clone_from_original_nid property is still + // attached to the node when passing through hook_node_insert(). + if (!empty($form['#node']->clone_from_original_nid)) { + $form['clone_from_original_nid'] = array( + '#type' => 'value', + '#value' => $form['#node']->clone_from_original_nid, + ); + } +} + +/** + * Implements hook_form_FORM_ID_alter(). + */ +function clone_form_node_admin_content_alter(&$form, $form_state, $form_id) { + if (variable_get('clone_method', 'prepopulate') == 'prepopulate') { + $destination = drupal_get_destination(); + } + else { + $destination = array(); + } + // The property attribute changes in the $form array depending on the user role. + $property = isset($form['admin']['nodes']['#options']) ? '#options' : '#rows'; + if (empty($form['admin']['nodes'][$property])) { + return; + } + // Expose a Clone operation on each node. + foreach ($form['admin']['nodes'][$property] as $nid => &$row) { + $node = node_load($nid); + if (clone_access_cloning($node)) { + // The structure of this form is different if there is just 1 or more + // than one operation. + if (!isset($row['operations']['data']['#links'])) { + $row['operations']['data']['#links'] = array(); + $row['operations']['data']['#attributes']['class'] = array('links', 'inline'); + $row['operations']['data']['#theme'] = 'links__node_operations'; + if (isset($row['operations']['data']['#title'])) { + $title = $row['operations']['data']['#title']; + $row['operations']['data']['#links'][$title] = array( + 'title' => $title, + 'href' => $row['operations']['data']['#href'], + 'query' => $row['operations']['data']['#options']['query'], + ); + unset($row['operations']['data']['#type']); + } + } + $row['operations']['data']['#links']['clone'] = array( + 'title' => t('clone'), + 'href' => 'node/' . $nid . '/clone/' . clone_get_token($nid), + 'query' => $destination, + ); + } + } +} + +/** + * Implements hook_action_info(). + */ +function clone_action_info() { + return array( + 'clone_action_clone' => array( + 'type' => 'node', + 'label' => t('Clone item'), + 'configurable' => TRUE, + 'hooks' => array('any' => TRUE), + 'triggers' => array('any'), + ), + ); +} + +/** + * Action callback. + */ +function clone_action_clone($original_node, $context) { + module_load_include('inc', 'clone', 'clone.pages'); + if (clone_is_permitted($original_node->type)) { + $val = !empty($context['clone_context']) ? $context['clone_context'] : array(); + $node = _clone_node_prepare($original_node, !empty($val['prefix_title'])); + if (isset($val['substitute_from']) && strlen($val['substitute_from']) && isset($val['substitute_to'])) { + $i = (!empty($val['substitute_case_insensitive']) ? 'i' : ''); + $pattern = '#' . strtr($val['substitute_from'], array('#' => '\#')) . '#' . $i; + foreach (array('title') as $property) { + $new = preg_replace($pattern, $val['substitute_to'], $node->{$property}); + if ($new) { + $node->{$property} = $new; + } + } + foreach (array('body') as $property) { + foreach ($node->{$property} as $lang => $row) { + foreach ($row as $delta => $data) { + foreach (array('value', 'summary') as $key) { + if (isset($node->{$property}[$lang][$delta][$key])) { + $new = preg_replace($pattern, $val['substitute_to'], $node->{$property}[$lang][$delta][$key]); + if ($new) { + $node->{$property}[$lang][$delta][$key] = $new; + } + } + } + } + } + } + } + // Let other modules do special fixing up. + $context = array('method' => 'action', 'original_node' => $original_node, 'clone_context' => $val); + drupal_alter('clone_node', $node, $context); + node_save($node); + if (module_exists('rules')) { + rules_invoke_event('clone_node', $node, $original_node); + } + } + else { + drupal_set_message(t('Clone failed for %title : not permitted for nodes of type %type', array('%title' => $original_node->title, '%type' => $original_node->type)), 'warning'); + } +} + +/** + * Action form. + */ +function clone_action_clone_form($context) { + $form['clone_context'] = array( + '#tree' => TRUE, + ); + $form['clone_context']['prefix_title'] = array( + '#title' => t('Prefix title'), + '#type' => 'checkbox', + '#description' => t('Should cloned node tiles be prefixed?'), + '#default_value' => isset($context['clone_context']['prefix_title']) ? $context['clone_context']['prefix_title'] : 1, + ); + $form['clone_context']['substitute_from'] = array( + '#title' => t('Substitute from string'), + '#type' => 'textfield', + '#description' => t('String (or regex) to substitute from in title and body.'), + '#default_value' => isset($context['clone_context']['substitue_from']) ? $context['clone_context']['substitue_from'] : '', + ); + $form['clone_context']['substitute_to'] = array( + '#title' => t('Substitute to string'), + '#type' => 'textfield', + '#description' => t('String (or regex) to substitute to in title and body.'), + '#default_value' => isset($context['clone_context']['substitue_to']) ? $context['clone_context']['substitue_to'] : '', + ); + $form['clone_context']['substitute_case_insensitive'] = array( + '#title' => t('Case insensitive substitution'), + '#type' => 'checkbox', + '#description' => t('Should the substituion match be case insensitive?'), + '#default_value' => isset($context['clone_context']['substitute_case_insensitive']) ? $context['clone_context']['substitute_case_insensitive'] : NULL, + ); + return $form; +} + +/** + * Action form submit. + */ +function clone_action_clone_submit($form, $form_state) { + return array('clone_context' => $form_state['values']['clone_context']); +} diff --git a/sites/all/modules/contrib/admin/node_clone/clone.pages.inc b/sites/all/modules/contrib/admin/node_clone/clone.pages.inc new file mode 100644 index 00000000..f90ecf1f --- /dev/null +++ b/sites/all/modules/contrib/admin/node_clone/clone.pages.inc @@ -0,0 +1,258 @@ + 'fieldset', + '#title' => t('General settings'), + ); + $form['basic']['clone_method'] = array( + '#type' => 'radios', + '#title' => t('Method to use when cloning a node'), + '#options' => array('prepopulate' => t('Pre-populate the node form fields'), 'save-edit' => t('Save as a new node then edit')), + '#default_value' => variable_get('clone_method', 'prepopulate'), + ); + $form['basic']['clone_nodes_without_confirm'] = array( + '#type' => 'radios', + '#title' => t('Confirmation mode when using the "Save as a new node then edit" method'), + '#default_value' => (int)variable_get('clone_nodes_without_confirm', 0), + '#options' => array(t('Require confirmation (recommended)'), t('Bypass confirmation')), + '#description' => t('A new node may be saved immediately upon clicking the "clone" link when viewing a node, bypassing the normal confirmation form.'), + '#states' => array( + // Only show this field when the clone method is save-edit. + 'visible' => array( + ':input[name="clone_method"]' => array('value' => 'save-edit'), + ), + ), + ); + $form['basic']['clone_menu_links'] = array( + '#type' => 'radios', + '#title' => t('Clone menu links'), + '#options' => array(0 => t('No'), 1 => t('Yes')), + '#default_value' => (int) variable_get('clone_menu_links', 0), + '#description' => t('Should any menu link for a node also be cloned?'), + ); + $form['basic']['clone_use_node_type_name'] = array( + '#type' => 'checkbox', + '#title' => t('Use node type name in clone link'), + '#default_value' => (int) variable_get('clone_use_node_type_name', 0), + '#description' => t('If checked, the link to clone the node will contain the node type name, for example, "Clone this article", otherwise it will read "Clone content".'), + ); + + $form['publishing'] = array( + '#type' => 'fieldset', + '#title' => t('Should the publishing options ( e.g. published, promoted, etc) be reset to the defaults?'), + ); + $types = node_type_get_names(); + + foreach ($types as $type => $name) { + $form['publishing']['clone_reset_' . $type] = array( + '#type' => 'checkbox', + '#title' => t('@s: reset publishing options when cloned', array('@s' => $name)), + '#default_value' => variable_get('clone_reset_' . $type, FALSE), + ); + } + + // Need the variable default key to be something that's never a valid node type. + $form['omit'] = array( + '#type' => 'fieldset', + '#title' => t('Content types that are not to be cloned - omitted due to incompatibility'), + ); + $form['omit']['clone_omitted'] = array( + '#type' => 'checkboxes', + '#title' => t('Omitted content types'), + '#default_value' => variable_get('clone_omitted', array()), + '#options' => $types, + '#description' => t('Select any node types which should never be cloned. In other words, all node types where cloning will fail.'), + ); + + return system_settings_form($form); +} + +/** + * Menu callback: prompt the user to confirm the operation + */ +function clone_node_check($node) { + + $method = variable_get('clone_method', 'prepopulate'); + + switch ($method) { + case 'save-edit': + if (variable_get('clone_nodes_without_confirm', FALSE)) { + $new_nid = clone_node_save($node->nid); + $options = array(); + if (!empty($_GET['node-clone-destination'])) { + $options['query']['destination'] = $_GET['node-clone-destination']; + } + drupal_goto('node/' . $new_nid . '/edit', $options); + } + else { + return drupal_get_form('clone_node_confirm', $node); + } + break; + case 'prepopulate': + default: + return clone_node_prepopulate($node); + break; + } +} + +/** + * form builder: prompt the user to confirm the operation + */ +function clone_node_confirm($form, &$form_state, $node) { + + $form['nid'] = array('#type' => 'value', '#value' => $node->nid); + return confirm_form($form, + t('Are you sure you want to clone %title?', array('%title' => $node->title)), + 'node/' . $node->nid, '' . t('This action will create a new node. You will then be redirected to the edit page for the new node.') . '
', + t('Clone'), t('Cancel')); +} + +/** + * Handle confirm form submission + */ +function clone_node_confirm_submit($form, &$form_state) { + if ($form_state['values']['confirm']) { + $new_nid = clone_node_save($form_state['values']['nid']); + } + $form_state['redirect'] = 'node/' . $new_nid . '/edit'; +} + + +/** + * Create a new menu link cloned from another node. + * + * Returns NULL if no existing link, or links are not to be cloned. + */ +function clone_node_clone_menu_link($node) { + if (variable_get('clone_menu_links', FALSE) && function_exists('menu_node_prepare')) { + // This will fetch the existing menu link if the node had one. + menu_node_prepare($node); + + if (!empty($node->menu['mlid'])) { + $old_link = $node->menu; + $link['link_title'] = t('Clone of !title', array('!title' => $old_link['link_title'])); + $link['plid'] = $old_link['plid']; + $link['menu_name'] = $old_link['menu_name']; + $link['weight'] = $old_link['weight']; + $link['module'] = $old_link['module']; + // Use the value -1 because it casts to boolean TRUE in function + // menu_form_node_form_alter() in menu.module so the node form checkbox + // is selected, but in function menu_link_save() no existing link will + // match. + $link['mlid'] = -1; + $link['has_children'] = 0; + $link['hidden'] = $old_link['hidden']; + $link['customized'] = $old_link['customized']; + $link['options'] = $old_link['options']; + $link['expanded'] = $old_link['expanded']; + $link['description'] = $old_link['description']; + $link['language'] = isset($old_link['language']) ? $old_link['language'] : NULL; + // This is needed to get the link saved in function menu_node_save() when + // using the save-edit method. + $link['enabled'] = TRUE; + return $link; + } + } + return NULL; +} + +/** + * Clones a node - prepopulate a node editing form + */ +function clone_node_prepopulate($original_node) { + if (isset($original_node->nid)) { + + if (clone_is_permitted($original_node->type)) { + $node = _clone_node_prepare($original_node, TRUE); + drupal_set_title($node->title); + // Let other modules do special fixing up. + $context = array('method' => 'prepopulate', 'original_node' => $original_node); + drupal_alter('clone_node', $node, $context); + // Make sure the file defining the node form is loaded. + $form_state = array(); + $form_state['build_info']['args'] = array($node); + form_load_include($form_state, 'inc', 'node', 'node.pages'); + return drupal_build_form($node->type . '_node_form', $form_state); + } + } +} + +/** + * Clones a node by directly saving it. + */ +function clone_node_save($nid, $account = NULL) { + if (is_numeric($nid)) { + + $original_node = node_load($nid); + if (isset($original_node->nid) && clone_is_permitted($original_node->type)) { + $node = _clone_node_prepare($original_node, TRUE, $account); + // Let other modules do special fixing up. + $context = array('method' => 'save-edit', 'original_node' => $original_node); + drupal_alter('clone_node', $node, $context); + + node_save($node); + if (module_exists('rules')) { + rules_invoke_event('clone_node', $node, $original_node); + } + return $node->nid; + } + } +} + +/** + * Prepares a node to be cloned. + */ +function _clone_node_prepare($original_node, $prefix_title = FALSE, $account = NULL) { + $node = clone $original_node; + + if (!isset($account->uid)) { + $account = $GLOBALS['user']; + } + + $node->nid = NULL; + $node->vid = NULL; + $node->tnid = NULL; + $node->log = NULL; + // Also handle modules that attach a UUID to the node. + $node->uuid = NULL; + $node->vuuid = NULL; + + // Anyonmymous users don't have a name. + // @see: drupal_anonymous_user(). + $node->name = isset($account->name) ? $account->name : NULL; + $node->uid = $account->uid; + + $node->created = NULL; + $node->menu = clone_node_clone_menu_link($original_node); + if (isset($node->book['mlid'])) { + $node->book['mlid'] = NULL; + $node->book['has_children'] = 0; + } + $node->path = NULL; + $node->files = array(); + if ($prefix_title) { + $node->title = t('Clone of !title', array('!title' => $node->title)); + } + // Add an extra property as a flag. + $node->clone_from_original_nid = $original_node->nid; + + if (variable_get('clone_reset_' . $node->type, FALSE)) { + $node_options = variable_get('node_options_' . $node->type, array('status', 'promote')); + // Fill in the default values. + foreach (array('status', 'moderate', 'promote', 'sticky', 'revision') as $key) { + // Cast to int since that's how they need to be saved to the DB. + $node->$key = (int) in_array($key, $node_options); + } + } + return $node; +} + diff --git a/sites/all/modules/contrib/admin/node_clone/clone.rules.inc b/sites/all/modules/contrib/admin/node_clone/clone.rules.inc new file mode 100644 index 00000000..fa4c27f1 --- /dev/null +++ b/sites/all/modules/contrib/admin/node_clone/clone.rules.inc @@ -0,0 +1,62 @@ + array( + 'label' => t('After cloning a node'), + 'group' => t('Node'), + 'variables' => array( + 'cloned_node' => array('type' => 'node', 'label' => t('The cloned node')), + 'original_node' => array('type' => 'node', 'label' => t('The original node')), + ), + ), + ); + return $items; +} + +/** + * Implements hook_rules_action_info(). + */ +function clone_rules_action_info() { + $actions = array( + 'clone_action_node_clone' => array( + 'label' => t('Clone a node'), + 'group' => t('Node'), + 'parameter' => array( + 'node' => array( + 'type' => 'node', + 'label' => t('Node to clone'), + ), + ), + 'provides' => array( + 'clone' => array( + 'type' => 'node', + 'label' => t('Cloned node'), + ), + ), + ), + ); + return $actions; +} + +/** + * Action callback for cloning a node. + * @param $node + * The node to clone. + */ +function clone_action_node_clone($node) { + include_once drupal_get_path('module', 'clone') . '/clone.pages.inc'; + $new_nid = clone_node_save($node->nid); + $new_node = entity_load_single('node', $new_nid); + return array( + 'clone' => $new_node, + ); +} diff --git a/sites/all/modules/contrib/admin/node_clone/views/clone.views.inc b/sites/all/modules/contrib/admin/node_clone/views/clone.views.inc new file mode 100644 index 00000000..bfdb6865 --- /dev/null +++ b/sites/all/modules/contrib/admin/node_clone/views/clone.views.inc @@ -0,0 +1,18 @@ + array( + 'title' => t('Clone link'), + 'help' => t('Provide a simple link to clone the node.'), + 'handler' => 'views_handler_field_node_link_clone', + ), + ); +} diff --git a/sites/all/modules/contrib/admin/node_clone/views/views_handler_field_node_link_clone.inc b/sites/all/modules/contrib/admin/node_clone/views/views_handler_field_node_link_clone.inc new file mode 100644 index 00000000..6b0f4f53 --- /dev/null +++ b/sites/all/modules/contrib/admin/node_clone/views/views_handler_field_node_link_clone.inc @@ -0,0 +1,37 @@ +options['alter']['make_link'] = TRUE; + $this->options['alter']['path'] = "node/{$node->nid}/clone/" . clone_get_token($node->nid); + $method = variable_get('clone_method', 'prepopulate'); + $destination = drupal_get_destination(); + if ($method == 'prepopulate') { + $this->options['alter']['query'] = $destination; + } + elseif (!empty($destination['destination'])) { + $this->options['alter']['query']['node-clone-destination'] = $destination['destination']; + } + + $text = !empty($this->options['text']) ? $this->options['text'] : t('clone'); + return $text; + } +} diff --git a/sites/all/modules/contrib/dev/elements/LICENSE.txt b/sites/all/modules/contrib/dev/elements/LICENSE.txt new file mode 100644 index 00000000..d159169d --- /dev/null +++ b/sites/all/modules/contrib/dev/elements/LICENSE.txt @@ -0,0 +1,339 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Lesser General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + +CER's purpose is to keep reference fields synchronized with each other. +For example, if you have a node ("Alice") with a user reference field, +and a user ("Bob") with a node reference field, and you make Alice +reference Bob, CER will automatically give Bob a back-reference to Alice. If +Alice subsequently dereferences Bob, Bob will automatically deference Alice. +Or, if Alice is deleted, Bob will lose his reference to Alice. CER does all +this transparently.
+ +CER is a powerful module. It lets you create relationships between different +"reference-type" fields. A reference-type field is, simply, +any kind of field that references another entity. Out of the box, CER supports +Entity Reference, Node Reference, User Reference, and core Taxonomy Term +Reference fields. It also includes a pair of add-on modules supporting Profile2 +and Commerce Product Reference fields. CER also has an object-oriented plugin +API that you can leverage if you need to support other types of reference +fields or alter CER's behavior. (More information about CER's API +can be found in cer.api.php.)
diff --git a/sites/all/modules/contrib/fields/cer/help/presets.html b/sites/all/modules/contrib/fields/cer/help/presets.html new file mode 100644 index 00000000..1d9d2759 --- /dev/null +++ b/sites/all/modules/contrib/fields/cer/help/presets.html @@ -0,0 +1,49 @@ +When you install CER, it won’t do anything at all until you create at least +one preset. A preset is a relationship between two reference field +instances, which are referred to as the left and right fields, respectively. +When a change occurs in the left field, the right field will react — and +vice-versa.
+ +An example: suppose you have a user reference field called Author, and it +lives on Page nodes. You also have a node reference field called My Pages, and +it lives on users. You can set up a preset that looks like this:
+ +Node: Page: Author <--> User: My Pages
+ +In this case, Author is the left field and My Pages is the right field. When +the Author field is changed on a Page node, the referenced user(s) will be +given a back-reference to that node.
+ +By default, presets are bidirectional. This means that a change +on either side of the preset will affect the other side. The previous example +is bidirectional: you can change Author or My Pages, and the other side +will react accordingly.
+ +It's possible to make a preset one-directional, which means that +the right side will react when the left side changes, but NOT the other way +around. In a one-directional preset, changes to the right field will have no +effect on the left field.
+ +A one-directional version of the above example would look like this:
+ +Node: Page: Author —> User: My Pages
+ +So what this means is that, in a bidirectional preset, it really doesn't +matter which field is the left one and which is the right one. They’ll affect +each other equally. But in a one-directional preset, it does matter +which side you're on. CER allows you to "invert" (flip) a +one-directional preset.
+ +Internally, CER treats all reference-type fields the same way, which allows +you to put a different kind of field on either side of a preset. You don't +have to necessarily relate a node reference field to another node reference +field. You could relate a node reference field to a user reference field. The +only restriction is that each side of the preset must be able to reference the +other side. So, to again use our example, Author needs to be able to reference +users, and My Pages needs to be able to reference nodes (of the Page type). +CER won't let you create relationships between fields that can’t actually +relate.
+ +CER presets are entities built on top of Entity API, and they can be +imported and exported just like any other exportable entity type, including +support for Features.
diff --git a/sites/all/modules/contrib/fields/cer/includes/CerEndPointIterator.inc b/sites/all/modules/contrib/fields/cer/includes/CerEndPointIterator.inc new file mode 100644 index 00000000..94a29be0 --- /dev/null +++ b/sites/all/modules/contrib/fields/cer/includes/CerEndPointIterator.inc @@ -0,0 +1,82 @@ +field = $field; + $this->handler = $field->getHandler($entity); + } + + /** + * Implements Iterator::current(). + */ + public function current() { + return $this->field->child()->getHandler($this->handler->current()); + } + + /** + * Implements Iterator::key(). + */ + public function key() { + return $this->handler->key(); + } + + /** + * Implements Iterator::next(). + */ + public function next() { + $this->handler->next(); + } + + /** + * Implements Iterator::rewind(). + */ + public function rewind() { + $this->handler->rewind(); + } + + /** + * Implements Iterator::handler(). + */ + public function valid() { + return $this->handler->valid(); + } + + /** + * Implements RecursiveIterator::hasChildren(). + */ + public function hasChildren() { + return ($this->field->child() instanceof CerEntityContainerInterface); + } + + /** + * Implements RecursiveIterator::getChildren(). + */ + public function getChildren() { + return new CerEndPointIterator($this->field->child(), $this->handler->current()); + } + +} diff --git a/sites/all/modules/contrib/fields/cer/includes/CerEntityContainerInterface.inc b/sites/all/modules/contrib/fields/cer/includes/CerEntityContainerInterface.inc new file mode 100644 index 00000000..68fe2fb1 --- /dev/null +++ b/sites/all/modules/contrib/fields/cer/includes/CerEntityContainerInterface.inc @@ -0,0 +1,24 @@ +plugin = $plugin; + + list ($entity_type, $bundle, $field_name) = explode(':', $plugin['identifier']); + parent::__construct($entity_type, $bundle, $field_name); + + // Store a copy of the field settings for convenience. At the time of this + // writing, this is needed by the Entity Reference, Node Reference, + // and Term Reference plugins. + $info = field_info_field($this->name); + $this->settings = $info['settings']; + + $type_info = field_info_field_types($info['type']); + $this->fieldTypeLabel = $type_info['label']; + } + + /** + * Returns a CerFieldHandler subclass instance for the given entity. + * + * @param object $entity + * The entity to be wrapped by the handler. + * + * @return CerFieldHandler + */ + public function getHandler(EntityDrupalWrapper $entity) { + return new $this->plugin['handler']($this, $entity); + } + + /** + * Returns the bundles that this field instance can reference. + * + * @return array + */ + public function getTargetBundles() { + $info = entity_get_info($this->getTargetType()); + return array_keys($info['bundles']); + } + + /** + * Overridden. + */ + public function requireParent() { + return $this->plugin['require parent']; + } + + /** + * Overridden. + */ + public function getParents() { + return array_map('CerField::getPlugin', $this->plugin['parents']); + } + + /** + * Returns information about a particular field plugin by its identifier, or all + * available plugins (i.e., defined by hook_cer_fields()) if no identifier is given. + * The aggregated result of hook_cer_fields() is statically cached. + */ + public static function getPluginInfo($identifier = NULL) { + $info = &drupal_static(__METHOD__); + + if (! isset($info)) { + $info = module_invoke_all('cer_fields'); + + foreach ($info as $key => &$field) { + $field += array( + 'identifier' => + $key, + 'parents' => + array(), + 'require parent' => + FALSE, + 'handler' => + 'CerFieldHandler', + ); + } + drupal_alter('cer_fields', $info); + } + + return ($identifier ? (isset($info[$identifier]) ? $info[$identifier] : NULL) : $info); + } + + /** + * Returns a single field plugin instance, by its identifier. All plugin instances + * are statically cached. + * + * @param string $identifier + * The plugin's identifier, in the format entity_type:bundle:field_name. + * + * @return CerField + * + * @throws Exception if there's no plugin for the given identifier. Why so harsh, you + * ask? Because CerFieldChain::unpack() utterly depends on being able to get plugin + * instances for every field in the chain, and if it can't, it could result in myriad + * weird and serious problems. Throwing an exception will head that off at the pass. + */ + public static function getPlugin($identifier) { + $instances = &drupal_static(__METHOD__); + + if (! isset($instances[$identifier])) { + $info = self::getPluginInfo($identifier); + if ($info) { + $instances[$identifier] = new $info['class']($info); + } + else { + throw new Exception("Cannot get instance of invalid plugin $identifier."); + } + } + + return $instances[$identifier]; + } + +} diff --git a/sites/all/modules/contrib/fields/cer/includes/CerFieldChain.inc b/sites/all/modules/contrib/fields/cer/includes/CerFieldChain.inc new file mode 100644 index 00000000..f168a024 --- /dev/null +++ b/sites/all/modules/contrib/fields/cer/includes/CerFieldChain.inc @@ -0,0 +1,91 @@ +end(); + return '/^' . $end->getTargetType() . ':(' . implode('|', $end->getTargetBundles()) . '):/'; + } + + /** + * Returns a Features export pipe for this chain, including every field and + * field instance in it. + */ + public function export() { + $pipe = array(); + + foreach ($this->chain as $field) { + $pipe['field_instance'][] = "{$field->entityType}-{$field->bundle}-{$field->name}"; + } + + return $pipe; + } + + /** + * Returns an array of every possible field chain for every field defined in + * hook_cer_fields(). + * + * @return array + */ + public static function collectAll() { + $chains = array(); + + foreach (array_keys(CerField::getPluginInfo()) as $identifier) { + $chains = array_merge($chains, self::collect($identifier)); + } + + return $chains; + } + + /** + * Returns an array of every possible field chain for a single field, + * identified by its key in hook_cer_fields(). + * + * @return array + */ + public static function collect($identifier) { + $chains = array(); + + $chain = new CerFieldChain(); + $chain->addField(CerField::getPlugin($identifier), $chains); + + return $chains; + } + + /** + * Constructs and returns a CerFieldChain object from an encoded string + * of field plugin identifiers glued together with ::. + * + * @return CerFieldChain + */ + public static function unpack($identifier) { + $chain = new CerFieldChain(); + + foreach (array_reverse(explode('::', $identifier)) as $field) { + $chain->addField(CerField::getPlugin($field)); + } + + return $chain; + } + +} + \ No newline at end of file diff --git a/sites/all/modules/contrib/fields/cer/includes/CerFieldChainHandler.inc b/sites/all/modules/contrib/fields/cer/includes/CerFieldChainHandler.inc new file mode 100644 index 00000000..c5df4627 --- /dev/null +++ b/sites/all/modules/contrib/fields/cer/includes/CerFieldChainHandler.inc @@ -0,0 +1,107 @@ +chain = $chain; + $this->entity = $entity; + + $chain->__wakeup(); + $chain->seek($entity->cer->depth->value()); + + $field = $chain->current(); + + // If the field has a child, there could be extensive recusion here. So we'll need + // to iterate over the entire chain recursively -- luckily, SPL provides the + // RecursiveIteratorIterator class for this purpose. But if there are no children, + // we don't need to recurse; the only handler we'll need to load is the current + // field's, for the current entity. + if ($field->child()) { + $this->handlers = new RecursiveIteratorIterator(new CerEndPointIterator($field, $entity)); + } + else { + // Wrap the handler in an array, just to normalize things internally. + $this->handlers = array( $field->getHandler($entity) ); + } + } + + /** + * Returns the IDs of every entity referenced in this chain. If there are no references, + * an empty array is returned. + * + * @return array + */ + public function getIDs() { + $IDs = array(); + + foreach ($this->handlers as $handler) { + $IDs = array_merge($handler->getIDs(), $IDs); + } + + return array_unique($IDs); + } + + /** + * Adds a reference to the given entity. + */ + public function add(EntityDrupalWrapper $entity) { + $owner = $this->entity; + + foreach ($this->chain as $field) { + // If the current field implements CerEntityContainerInterface, we can + // create an entity on-the-fly to receive the reference, if there isn't + // one already. + if ($field instanceof CerEntityContainerInterface) { + $items = $field->getHandler($owner); + + // If there is are items which could receive the reference, seek to the + // last one. Otherwise, create one. + if (sizeof($items) == 0) { + $owner = $field->createInnerEntity($owner); + } + else { + $items->seek(-1); + $owner = $items->current(); + } + } + } + + $field->getHandler($owner)->add($entity); + } + + public function delete(EntityDrupalWrapper $entity) { + foreach ($this->handlers as $handler) { + $handler->delete($entity); + } + } + +} diff --git a/sites/all/modules/contrib/fields/cer/includes/CerFieldHandler.inc b/sites/all/modules/contrib/fields/cer/includes/CerFieldHandler.inc new file mode 100644 index 00000000..8521e271 --- /dev/null +++ b/sites/all/modules/contrib/fields/cer/includes/CerFieldHandler.inc @@ -0,0 +1,306 @@ +field = $field; + $this->entity = $entity; + $this->value = $entity->{ $field->name }; + $this->isMultiValue = ($this->value instanceof EntityListWrapper); + + $this->rewind(); + } + + /** + * Adds a reference to $entity, validating it first. + * + * @param EntityDrupalWrapper $entity + * The wrapped entity to reference. + */ + public function add(EntityDrupalWrapper $entity) { + if ($this->validate($entity)) { + $this->write(); + } + } + + /** + * Deletes all references to $entity. + * + * @param EntityDrupalWrapper $entity + * The wrapped entity to dereference. + */ + public function delete(EntityDrupalWrapper $entity) { + $entityID = $entity->getIdentifier(); + + if ($this->isMultiValue) { + foreach ($this->value as $delta => $ref) { + if ($entityID == $ref->getIdentifier()) { + $this->value[$delta]->set(NULL); + } + } + } + elseif ($entityID == $this->value->getIdentifier()) { + $this->value->set(NULL); + } + + $this->write(); + } + + /** + * Validates a potential reference. After doing a cardinality check, the + * reference is validated through the Field Attach API, allowing the module + * which owns the field to do its normal validation logic. If validation + * fails, the error(s) are logged. + * + * @param EntityDrupalWrapper $entity + * The wrapped entity to validate. + * + * @return boolean + */ + protected function validate(EntityDrupalWrapper $entity) { + // Before we do anything else, check that the field has enough space to add the + // reference. If there isn't, bail out so we don't blindly overwrite existing + // field data. + if ($this->checkCardinality()) { + // Keep the previous value so we can restore it if validation fails. + $prev_value = $this->value->value(); + + if ($this->isMultiValue) { + $value = $this->value->value(); + $value[] = $entity->value(); + $this->value->set($value); + } + else { + $this->value->set( $entity->value() ); + } + + // Leverage the Field Attach API to validate the reference. If errors occur, + // field_attach_validate() throws FieldValidationException, containing an array + // of every validation error. + try { + // Only validate this field. + field_attach_validate($this->entity->type(), $this->entity->value(), array('field_name' => $this->field->name)); + + return TRUE; + } + catch (FieldValidationException $e) { + foreach ($e->errors as $field) { + foreach ($field as $language) { + foreach ($language as $errors) { + foreach ($errors as $error) { + $this->logError($error['message'], $entity); + } + } + } + } + $this->value->set($prev_value); + } + } + else { + $this->logError('Cannot add reference to !that_link from !field_label on !this_link because there are no more slots available.', $entity); + } + + return FALSE; + } + + /** + * Checks that there are enough slots in the field to add a reference. + * + * @return boolean + */ + protected function checkCardinality() { + return ($this->field->cardinality == FIELD_CARDINALITY_UNLIMITED ? TRUE : ($this->field->cardinality > $this->count())); + } + + /** + * Saves changes to the entity and resets the iterator. + */ + protected function write() { + $entity_type = $this->entity->type(); + $entityID = $this->entity->getIdentifier(); + $entity = $this->entity->value(); + + $entity->cer_processed = TRUE; + entity_save($entity_type, $entity); + + // Reload the entity we just saved and cleared from the static cache. + $entities = entity_load($entity_type, (array) $entityID); + $this->entity->set($entities[$entityID]); + + $this->__construct($this->field, $this->entity); + } + + /** + * Logs an error, optionally against a specific entity. If the cer_debug + * variable is set, the error will also be set as a message. + * + * @param string $message + * The untranslated message to log. + * + * @param EntityDrupalWrapper $entity + * The entity that has caused the error, if any. + */ + protected function logError($message, EntityDrupalWrapper $entity = NULL) { + $variables = array( + '!field_name' => $this->field->name, + '!field_type' => $this->field->fieldTypeLabel, + '!field_label' => $this->field->label, + ); + + $variables['!this_type'] = $this->entity->type(); + $variables['!this_label'] = $this->entity->label(); + + // If the entity has a URI, provide a link to it. Otherwise, its "link" + // will just be an unlinked label. Entity API doesn't reliably expose a url + // property on entities, and there doesn't appear to be a way to check for + // it without risking an EntityMetadataWrapperException. So I need to use + // this clunky BS instead...ugh. + $this_uri = entity_uri($this->entity->type(), $this->entity->value()); + if (isset($this_uri)) { + $variables['!this_url'] = url($this_uri['path'], $this_uri['options']); + $variables['!this_link'] = l($this->entity->label(), $this_uri['path'], $this_uri['options']); + } + else { + $variables['!this_link'] = $this->entity->label(); + } + + if ($entity) { + $variables['!that_type'] = $entity->type(); + $variables['!that_label'] = $entity->label(); + + // If the entity has a URI, link to it. + $that_uri = entity_uri($entity->type(), $entity->value()); + if (isset($that_uri)) { + $variables['!that_url'] = url($that_uri['path'], $that_uri['options']); + $variables['!that_link'] = l($entity->label(), $that_uri['path'], $that_uri['options']); + } + else { + $variables['!that_link'] = $entity->label(); + } + } + + watchdog('cer', $message, $variables, WATCHDOG_ERROR); + + if (variable_get('cer_debug', FALSE)) { + drupal_set_message(t($message, $variables), 'error'); + } + } + + public function getIDs() { + $IDs = array(); + + if ($this->isMultiValue) { + foreach ($this->value as $ref) { + $IDs[] = $ref->raw(); + } + } + else { + $IDs[] = $this->value->raw(); + } + + return array_unique(array_filter($IDs)); + } + + /** + * Implements Countable::count(). + */ + public function count() { + if ($this->isMultiValue) { + return sizeof($this->value); + } + else { + return ($this->value->value() ? 1 : 0); + } + } + + /** + * Implements SeekableIterator::seek(). + */ + public function seek($position) { + $length = $this->count(); + + if ($position < 0) { + $position += $length; + } + + if ($position >= 0 && $position < $length) { + $this->delta = $position; + } + else { + throw new OutOfBoundsException(t('Cannot seek to invalid position.')); + } + } + + /** + * Implements Iterator::current(). + */ + public function current() { + return ($this->isMultiValue ? $this->value[$this->delta] : $this->value); + } + + /** + * Implements Iterator::key(). + */ + public function key() { + return $this->current()->getIdentifier(); + } + + /** + * Implements Iterator::next(). + */ + public function next() { + $this->delta++; + } + + /** + * Implements Iterator::rewind(). + */ + public function rewind() { + $this->delta = 0; + } + + /** + * Implements Iterator::valid(). + */ + public function valid() { + return ($this->delta < $this->count()); + } + +} + \ No newline at end of file diff --git a/sites/all/modules/contrib/fields/cer/includes/CerPreset.inc b/sites/all/modules/contrib/fields/cer/includes/CerPreset.inc new file mode 100644 index 00000000..09cb9368 --- /dev/null +++ b/sites/all/modules/contrib/fields/cer/includes/CerPreset.inc @@ -0,0 +1,75 @@ +cer_left*$this->cer_right. + */ + public $identifier; + + /** + * @var EntityMetadataWrapper + * A metadata wrapper around this preset, for convenience. + */ + public $wrapper; + + /** + * @var integer + * The exportable status of this preset. + */ + public $status = 0x01; // ENTITY_CUSTOM + + /** + * @var string + * The module exporting this preset. + */ + public $module = 'cer'; + + /** + * Overrides Entity::__construct(). + */ + public function __construct(array $values = array()) { + parent::__construct($values, 'cer'); + $this->wrapper = new EntityDrupalWrapper('cer', $this); + } + + /** + * Overrides Entity::label(). + */ + public function label() { + return isset($this->label_variables) ? t('@left !operator @right', $this->label_variables) : $this->defaultLabel(); + } + + /** + * Overrides Entity::save(). + */ + public function save() { + // Generate the export identifier automagically before saving. + $this->identifier = $this->wrapper->cer_left->value() . '*' . $this->wrapper->cer_right->value(); + parent::save(); + } + + public function invert() { + $init = get_object_vars($this); + + unset($init['pid'], $init['wrapper'], $init['identifier'], $init['status']); + + $buf = $init['cer_left']; + $init['cer_left'] = $init['cer_right']; + $init['cer_right'] = $buf; + + return entity_create('cer', $init); + } +} diff --git a/sites/all/modules/contrib/fields/cer/includes/CerPresetController.inc b/sites/all/modules/contrib/fields/cer/includes/CerPresetController.inc new file mode 100644 index 00000000..958571d4 --- /dev/null +++ b/sites/all/modules/contrib/fields/cer/includes/CerPresetController.inc @@ -0,0 +1,50 @@ +label_variables = array( + '@left' => + render($fields['cer_left'][0]), + '@right' => + render($fields['cer_right'][0]), + '!operator' => + $preset->wrapper->cer_bidirectional->value() ? '<>' : '>', + ); + } + } + +} diff --git a/sites/all/modules/contrib/fields/cer/includes/CerPresetFeaturesController.inc b/sites/all/modules/contrib/fields/cer/includes/CerPresetFeaturesController.inc new file mode 100644 index 00000000..59303b72 --- /dev/null +++ b/sites/all/modules/contrib/fields/cer/includes/CerPresetFeaturesController.inc @@ -0,0 +1,26 @@ +type, $data) as $preset) { + $pipe = array_merge_recursive($pipe, $preset->wrapper->cer_left->chain->value()->export()); + $pipe = array_merge_recursive($pipe, $preset->wrapper->cer_right->chain->value()->export()); + } + + return $pipe; + } + +} diff --git a/sites/all/modules/contrib/fields/cer/includes/CerPresetFinder.inc b/sites/all/modules/contrib/fields/cer/includes/CerPresetFinder.inc new file mode 100644 index 00000000..c1372488 --- /dev/null +++ b/sites/all/modules/contrib/fields/cer/includes/CerPresetFinder.inc @@ -0,0 +1,71 @@ +entity = $entity; + + $this + ->entityCondition('entity_type', 'cer') + ->addTag('cer_presets') + ->addMetaData('entity', $entity); + } + + public function execute() { + $lineage = $this->entity->cer->lineage->value(); + + $this->result['cer'] = $this + ->fieldCondition('cer_enabled', 'value', TRUE) + ->fieldCondition('cer_left', 'path', $lineage, 'STARTS_WITH') + ->_load(parent::execute()); + + $this->fieldConditions = array(); + + $this->result['cer__invert'] = $this + ->fieldCondition('cer_enabled', 'value', TRUE) + ->fieldCondition('cer_bidirectional', 'value', TRUE) + ->fieldCondition('cer_right', 'path', $lineage, 'STARTS_WITH') + ->_load(parent::execute()); + + $result = $this->result['cer']; + foreach ($this->result['cer__invert'] as $preset) { + $result[] = $preset->invert(); + } + usort($result, array($this, '_sort')); + + return $result; + } + + private function _load(array $result) { + return isset($result['cer']) ? entity_load('cer', array_keys($result['cer'])) : array(); + } + + private function _sort(CerPreset $a, CerPreset $b) { + $a_weight = $a->wrapper->cer_weight->value(); + $b_weight = $b->wrapper->cer_weight->value(); + + if ($a_weight > $b_weight) { + return 1; + } + elseif ($b_weight > $a_weight) { + return -1; + } + else { + return 0; + } + } + +} diff --git a/sites/all/modules/contrib/fields/cer/includes/CerPresetHandler.inc b/sites/all/modules/contrib/fields/cer/includes/CerPresetHandler.inc new file mode 100644 index 00000000..d630cf2f --- /dev/null +++ b/sites/all/modules/contrib/fields/cer/includes/CerPresetHandler.inc @@ -0,0 +1,155 @@ +left = $preset->wrapper->cer_left->chain->value(); + $this->right = $preset->wrapper->cer_right->chain->value(); + $this->entity = $entity; + + // Store the current set of reference IDs so that we only need to instantiate + // the left handler once. + $this->refIDs = $this->left->getHandler( $entity )->getIDs(); + } + + /** + * Process an entity insert. This loops through the referenced entity $IDs and + * adds a reference to this entity if the reference doesn't already have one. + */ + public function insert(array $IDs = array()) { + // If no IDs were passed in, use the current reference set. + $IDs = ($IDs ? $IDs : $this->refIDs); + + // Get this entity's ID right now, so we don't have to keep calling + // $this->entity->cer->owner->getIdentifier(). Hooray for micro-optimization! + $myID = $this->entity->cer->owner->getIdentifier(); + + foreach ($this->load( $IDs ) as $ref) { + $handler = $this->right->getHandler( $ref ); + + // Only create the backreference if the reference doesn't already reference + // this entity (which it might, if there is more than one preset that references + // a single field instance). + if (! in_array($myID, $handler->getIDs())) { + $handler->add( $this->entity->cer->owner ); + } + } + } + + /** + * Process an entity update. This could be either a normal update done by a user, + * or a bulk update. + */ + public function update() { + // Get the previous set of reference IDs. $entity->cer->original will return either + // $entity->original, if it exists, or the current entity. So, if this is a bulk + // update, $originalIDs will be identical to $this->refIDs. + $originalIDs = $this->left->getHandler( $this->entity->cer->original )->getIDs(); + + // If there are any references that were in the previous set but not the current + // set, delete those backreferences. Under normal circumstances, there will be + // nothing to delete during a bulk update, since the previous set and current + // set should be identical. + $deleted = array_diff($originalIDs, $this->refIDs); + if ($deleted) { + $this->delete($deleted); + } + + // If the previous set is identical to the current set, we'll be processing + // all existing references (see the first line of $this->insert()). + $added = array_diff($this->refIDs, $originalIDs); + $this->insert($added); + } + + /** + * Process an entity delete. Loops through the referenced entity IDs and clears + * their references to this entity. + */ + public function delete(array $IDs = array()) { + // As with $this->insert(), we can process a specific set of references or + // everything in the current set. + $IDs = ($IDs ? $IDs : $this->refIDs); + + foreach ($this->load( $IDs ) as $ref) { + $this->right->getHandler( $ref )->delete( $this->entity->cer->owner ); + } + } + + /** + * Loads referenced entities. This might seem like a convenience method, but it + * is a critical part CER's core logic. + * + * @param array $IDs + * Array of entity IDs to load. + * + * @return array + * The requested entities, wrapped by EntityDrupalWrapper. If nothing could be + * loaded, an empty array is returned. + */ + protected function load(array $IDs) { + if (empty($IDs)) { + return array(); + } + + $this->right->rewind(); + $right = $this->right->current(); + $entity_type = $right->entityType; + + $query = new EntityFieldQuery(); + $query->entityCondition('entity_type', $entity_type); + $query->entityCondition('entity_id', $IDs); + + // If the right entity type has bundles, we need to filter by that too. If we don't, + // we could run into a bug where, if the left field can reference multiple bundles, + // we might try to modify the wrong entity. Essentially, the loading of referenced + // entities should be as targeted as possible to prevent ambiguities and buggery. + if ($right->isBundleable) { + $query->entityCondition('bundle', $right->bundle); + } + + $result = $query->execute(); + if (isset($result[$entity_type])) { + $result[$entity_type] = entity_load($entity_type, array_keys($result[$entity_type])); + + foreach ($result[$entity_type] as $id => $entity) { + $result[$entity_type][$id] = new EntityDrupalWrapper($entity_type, $entity); + } + + return $result[$entity_type]; + } + else { + return array(); + } + } + +} diff --git a/sites/all/modules/contrib/fields/cer/includes/CerUIController.inc b/sites/all/modules/contrib/fields/cer/includes/CerUIController.inc new file mode 100644 index 00000000..3423e499 --- /dev/null +++ b/sites/all/modules/contrib/fields/cer/includes/CerUIController.inc @@ -0,0 +1,220 @@ +path]['title'] = t('Corresponding Entity References'); + $items["{$this->path}/list"]['title'] = t('Presets'); + + $this->setTitle($items["{$this->path}/add"], t('Add preset')); + $this->setTitle($items["{$this->path}/import"], t('Import preset')); + + $items["{$this->path}/manage/%entity_object/toggle"] = $this->createCallback('cer_toggle_preset', 'update'); + $items["{$this->path}/manage/%entity_object/invert"] = $this->createCallback('cer_invert_preset', 'create'); + + // Don't provide a page for cloning a preset. + unset($items["{$this->path}/manage/%entity_object/clone"]); + + return $items; + } + + private function createCallback($function, $operation, array $init = array()) { + return $init + array( + 'type' => MENU_CALLBACK, + 'page callback' => $function, + 'page arguments' => array(5), + 'load arguments' => array('cer'), + 'access callback' => 'entity_access', + 'access arguments' => array($operation, 'cer'), + 'file' => 'cer.admin.inc', + 'file path' => drupal_get_path('module', 'cer'), + ); + } + + /** + * Sets a static title on a menu item. + */ + private function setTitle(array &$item, $title) { + $item['title'] = $title; + unset($item['title callback'], $item['title arguments']); + } + + public function operationForm($form, &$form_state, $entity, $action) { + switch ($action) { + case 'delete': + return confirm_form($form, t('Are you sure you want to delete this preset?'), $this->path, t('@left will no longer synchronize with @right.', $entity->label_variables)); + + default: + return parent::operationForm($form, $form_state, $entity, $action); + } + } + + public function overviewForm($form, &$form_state) { + $form = parent::overviewForm($form, $form_state); + + $form['actions'] = array( + 'update' => array( + '#type' => 'submit', + '#value' => t('Save changes'), + ), + '#type' => 'actions', + ); + + return $form; + } + + public function overviewFormSubmit($form, &$form_state) { + foreach ($form_state['values']['table'] as $id => $values) { + $preset = entity_object_load($id, $this->entityType); + + $preset->wrapper->cer_enabled->set($values['cer_enabled'][LANGUAGE_NONE][0]['value']); + $preset->wrapper->cer_bidirectional->set($values['cer_bidirectional'][LANGUAGE_NONE][0]['value']); + $preset->wrapper->cer_weight->set($values['cer_weight'][LANGUAGE_NONE][0]['value']); + + $preset->save(); + } + + drupal_set_message(t('The changes have been saved.')); + } + + public function overviewTable($conditions = array()) { + $render = array( + '#header' => array( + t('Left Field'), + t('Right Field'), + t('Status'), + t('Enabled'), + t('Bidirectional'), + t('Weight'), + t('Operations'), + ), + '#tabledrag' => array( + array( + 'action' => 'order', + 'relationship' => 'sibling', + 'group' => 'cer-weight', + ), + ), + '#empty' => t('None.'), + '#type' => 'table', + ); + + $query = new EntityFieldQuery(); + $query->entityCondition('entity_type', $this->entityType); + + // Add all conditions to query. + foreach ($conditions as $key => $value) { + $query->propertyCondition($key, $value); + } + + if ($this->overviewPagerLimit) { + $query->pager($this->overviewPagerLimit); + } + + $query->fieldOrderBy('cer_weight', 'value'); + + $results = $query->execute(); + $entities = isset($results['cer']) ? entity_load('cer', array_keys($results['cer'])) : array(); + + foreach ($entities as $entity) { + $render[$entity->pid] = $this->overviewTableRow($conditions, $entity->pid, $entity); + } + + return $render; + } + + protected function overviewTableRow($conditions, $id, $entity, $additional_cols = array()) { + $render_fields = field_attach_view($this->entityType, $entity, 'default'); + + $render_fields['cer_left']['#label_display'] = 'inline'; + $render_fields['cer_left']['#title'] = $entity->wrapper->cer_left->chain->value()->end()->fieldTypeLabel; + $row['cer_left'] = $render_fields['cer_left']; + + $render_fields['cer_right']['#label_display'] = 'inline'; + $render_fields['cer_right']['#title'] = $entity->wrapper->cer_right->chain->value()->end()->fieldTypeLabel; + $row['cer_right'] = $render_fields['cer_right']; + + $row['status'] = array( + '#theme' => 'entity_status', + '#status' => $entity->status, + ); + + $form_fields = array(); + $form_state = form_state_defaults(); + $form_state['build_info']['form_id'] = 'cer_overview_form'; + field_attach_form($this->entityType, $entity, $form_fields, $form_state); + + unset($form_fields['cer_enabled'][LANGUAGE_NONE]['#title']); + $row['cer_enabled'] = $form_fields['cer_enabled']; + + unset($form_fields['cer_bidirectional'][LANGUAGE_NONE]['#title']); + $row['cer_bidirectional'] = $form_fields['cer_bidirectional']; + + unset($form_fields['cer_weight'][LANGUAGE_NONE]['#title']); + $form_fields['cer_weight'][LANGUAGE_NONE]['#attributes']['class'][] = 'cer-weight'; + $row['cer_weight'] = $form_fields['cer_weight']; + + // Add in any passed additional cols. + foreach ($additional_cols as $key => $col) { + $row[$key] = $col; + } + + // I like drop buttons more than an inline set of links. + $links = array( + 'toggle' => array( + 'title' => $entity->wrapper->cer_enabled->value() ? t('disable') : t('enable'), + 'href' => "{$this->path}/manage/{$id}/toggle", + 'query' => drupal_get_destination(), + ), + 'edit' => array( + 'title' => t('edit'), + 'href' => "{$this->path}/manage/{$id}", + ), + ); + + // If the preset is one-directional, expose a link to invert it. + if (! $entity->wrapper->cer_bidirectional->value()) { + $links['invert'] = array( + 'title' => t('invert'), + 'href' => "{$this->path}/manage/{$id}/invert", + 'query' => drupal_get_destination(), + ); + } + + if (entity_has_status($this->entityType, $entity, ENTITY_OVERRIDDEN)) { + $links['revert'] = array( + 'title' => t('revert'), + 'href' => "{$this->path}/manage/{$id}/revert", + 'query' => drupal_get_destination(), + ); + } + else { + $links['delete'] = array( + 'title' => t('delete'), + 'href' => "{$this->path}/manage/{$id}/delete", + 'query' => drupal_get_destination(), + ); + } + $links['export'] = array( + 'title' => t('export'), + 'href' => "{$this->path}/manage/{$id}/export", + ); + + $row['operations'] = array( + '#theme' => 'links__ctools_dropbutton', + '#links' => $links, + ); + + $row['#attributes']['class'][] = 'draggable'; + + return $row; + } + +} diff --git a/sites/all/modules/contrib/fields/cer/includes/fields/entity_reference.inc b/sites/all/modules/contrib/fields/cer/includes/fields/entity_reference.inc new file mode 100644 index 00000000..abc5bf0c --- /dev/null +++ b/sites/all/modules/contrib/fields/cer/includes/fields/entity_reference.inc @@ -0,0 +1,55 @@ +settings['target_type']; + } + + /** + * @override CerField::getTargetBundles(). + */ + public function getTargetBundles() { + $bundles = array(); + + // If the reference field is using a view, load the view and see if it's filtering by the entity + // type's bundle filter. If it is, the filter values are the target bundles. Otherwise, + // assume that all bundles can be referenced. + // + // @todo Support contextual filters? + // + // NOTE: Selection handlers (i.e., $field['settings']['handler']) are plugins owned by + // Entity Reference. There is no method defined to get an array of referenceable + // bundles, but hopefully, if CER gains enough traction in the community, such a + // method can be added to the EntityReference_SelectionHandler interface. This + // function could then be deprecated, which would be a more flexible, future-proof + // method of finding a field's target bundles. + // + if ($this->settings['handler'] == 'views') { + $view = views_get_view($this->settings['handler_settings']['view']['view_name']); + $view->set_display($this->settings['handler_settings']['view']['display_name']); + + $info = entity_get_info($this->getTargetType()); + if (isset($info['entity keys']['bundle'])) { + $handler = $view->display_handler->get_handler('filter', $info['entity keys']['bundle']); + if ($handler) { + $bundles = $handler->value; + } + } + } + else { + $bundles = $this->settings['handler_settings']['target_bundles']; + } + + return ($bundles ? $bundles : parent::getTargetBundles()); + } + +} diff --git a/sites/all/modules/contrib/fields/cer/includes/fields/field_collection.inc b/sites/all/modules/contrib/fields/cer/includes/fields/field_collection.inc new file mode 100644 index 00000000..2a5b4099 --- /dev/null +++ b/sites/all/modules/contrib/fields/cer/includes/fields/field_collection.inc @@ -0,0 +1,39 @@ +name); + } + + /** + * Implements CerEntityContainerInterface::createInnerEntity(). + */ + public function createInnerEntity(EntityDrupalWrapper $owner) { + // Create an empty field collection item. + $collection = new EntityDrupalWrapper('field_collection_item', entity_create('field_collection_item', array('field_name' => $this->name))); + $collection->host_entity->set( $owner ); + $collection->save(TRUE); + + // 'Reference' the newly created field collection item. + $this->getHandler($owner)->add($collection); + + return $collection; + } + +} diff --git a/sites/all/modules/contrib/fields/cer/includes/fields/node_reference.inc b/sites/all/modules/contrib/fields/cer/includes/fields/node_reference.inc new file mode 100644 index 00000000..73efd166 --- /dev/null +++ b/sites/all/modules/contrib/fields/cer/includes/fields/node_reference.inc @@ -0,0 +1,41 @@ +settings['view']['view_name']; + if ($view) { + $view = views_get_view($view); + $view->set_display($this->settings['view']['view_display']); + + $handler = $view->display_handler->get_handler('filter', 'type'); + if ($handler) { + $bundles = $handler->value; + } + } + else { + $bundles = array_filter($this->settings['referenceable_types']); + } + + return ($bundles ? $bundles : parent::getTargetBundles()); + } + +} + \ No newline at end of file diff --git a/sites/all/modules/contrib/fields/cer/includes/fields/taxonomy_term_reference.inc b/sites/all/modules/contrib/fields/cer/includes/fields/taxonomy_term_reference.inc new file mode 100644 index 00000000..7aa40d2d --- /dev/null +++ b/sites/all/modules/contrib/fields/cer/includes/fields/taxonomy_term_reference.inc @@ -0,0 +1,30 @@ +settings['allowed_values'] as $item) { + $bundles[] = $item['vocabulary']; + } + + return $bundles; + } + +} diff --git a/sites/all/modules/contrib/fields/cer/includes/fields/user_reference.inc b/sites/all/modules/contrib/fields/cer/includes/fields/user_reference.inc new file mode 100644 index 00000000..8f44bb6e --- /dev/null +++ b/sites/all/modules/contrib/fields/cer/includes/fields/user_reference.inc @@ -0,0 +1,18 @@ +author. + * + * @var StdClass + */ + protected $node; + + public static function getInfo() { + return array( + 'name' => 'Basic', + 'description' => "Tests CER's basic CRUD functionality.", + 'group' => 'CER', + ); + } + + public function setUp() { + // Turns out you have to enable your own module in the friggin' test, if + // you want your own classes to be available. Lawsy me and other such + // utterances...SimpleTest is teh suck. + parent::setUp('entity', 'ctools', 'entityreference', 'field_object', 'cer'); + + $field = array( + 'type' => 'entityreference', + 'cardinality' => 1, + 'field_name' => 'field_author', + 'settings' => array( + 'target_type' => 'user', + ), + ); + field_create_field($field); + + $instance = array( + 'field_name' => $field['field_name'], + 'entity_type' => 'node', + 'bundle' => 'page', + ); + field_create_instance($instance); + + $field = array( + 'type' => 'entityreference', + 'cardinality' => FIELD_CARDINALITY_UNLIMITED, + 'field_name' => 'field_pages', + 'settings' => array( + 'target_type' => 'node', + ), + 'handler_settings' => array( + 'target_bundles' => array('page'), + ), + ); + field_create_field($field); + + $instance = array( + 'field_name' => $field['field_name'], + 'entity_type' => 'user', + 'bundle' => 'user', + ); + field_create_instance($instance); + + /** @var CerPreset $preset */ + $preset = entity_create('cer', array()); + $preset->wrapper->cer_left->set('node:page:field_author'); + $preset->wrapper->cer_right->set('user:user:field_pages'); + $preset->wrapper->cer_bidirectional->set(TRUE); + $preset->wrapper->cer_enabled->set(TRUE); + $preset->save(); + + $this->author = $this->drupalCreateUser(); + + $this->node = $this->drupalCreateNode(array( + 'field_author' => array( + LANGUAGE_NONE => array( + array('target_id' => $this->author->uid), + ), + ), + )); + } + + public function testCreate() { + $author = $this->reload('user', $this->author); + $this->assertEqual(1, $author->field_pages->count()); + $this->assertEqual($this->node->nid, $author->field_pages[0]->nid->value()); + } + + public function testUpdateDereference() { + // Dereference the node from the user. + $this->author->field_pages = array(); + user_save($this->author); + + // Reload $this->node from the database so we get the latest field values. + $this->assertNull($this->reload('node', $this->node)->field_author->value()); + } + + public function testUpdateChangeTarget() { + $target = $this->drupalCreateUser(); + + $this->node->field_author[LANGUAGE_NONE][0]['target_id'] = $target->uid; + node_save($this->node); + + // The original author should no longer reference the node. + $this->assertEqual(0, $this->reload('user', $this->author)->field_pages->count()); + + /** @var EntityDrupalWrapper $target */ + $target = $this->reload('user', $target); + $this->assertEqual(1, $target->field_pages->count()); + $this->assertEqual($this->node->nid, $target->field_pages[0]->nid->value()); + } + + public function testDelete() { + node_delete($this->node->nid); + $this->assertEqual(0, $this->reload('user', $this->author)->field_pages->count()); + } + + /** + * @return EntityDrupalWrapper + */ + protected function reload($entity_type, $entity) { + list ($id) = entity_extract_IDs($entity_type, $entity); + $entities = entity_load($entity_type, array($id), NULL, TRUE); + + return entity_metadata_wrapper($entity_type, $entities[$id]); + } + +} diff --git a/sites/all/modules/contrib/fields/cer/tests/cer_tests.info b/sites/all/modules/contrib/fields/cer/tests/cer_tests.info deleted file mode 100644 index 5e383b21..00000000 --- a/sites/all/modules/contrib/fields/cer/tests/cer_tests.info +++ /dev/null @@ -1,16 +0,0 @@ -name = "CER Tests" -core = "7.x" -description = "Automated tests for CER." -hidden = TRUE - -dependencies[] = simpletest -dependencies[] = cer - -files[] = crud.test -files[] = fields.test -; Information added by Drupal.org packaging script on 2014-08-08 -version = "7.x-2.x-dev" -core = "7.x" -project = "cer" -datestamp = "1407528862" - diff --git a/sites/all/modules/contrib/fields/cer/tests/cer_tests.module b/sites/all/modules/contrib/fields/cer/tests/cer_tests.module deleted file mode 100644 index b3d9bbc7..00000000 --- a/sites/all/modules/contrib/fields/cer/tests/cer_tests.module +++ /dev/null @@ -1 +0,0 @@ - 'CRUD', - 'group' => 'Corresponding Entity Reference', - 'description' => 'Tests basic CER functionality.', - ); - } - - public function setUp() { - parent::setUp('field', 'field_sql_storage', 'ctools', 'entityreference', 'cer'); - - field_create_field(array( - 'field_name' => 'field_user', - 'type' => 'entityreference', - 'cardinality' => -1, - 'settings' => array( - 'target_type' => 'user', - ), - )); - field_create_field(array( - 'field_name' => 'field_node', - 'type' => 'entityreference', - 'cardinality' => -1, - 'settings' => array( - 'target_type' => 'node', - ), - )); - - field_create_instance(array( - 'field_name' => 'field_user', - 'entity_type' => 'node', - 'bundle' => 'page', - )); - field_create_instance(array( - 'field_name' => 'field_node', - 'entity_type' => 'user', - 'bundle' => 'user', - )); - - db_insert('cer')->fields(array( - 'entity_types_content_fields' => 'node*page*field_user*user*user*field_node', - 'enabled' => TRUE, - ))->execute(); - } - - public function testImplicitReferenceCreation() { - $uid = $this->drupalCreateUser()->uid; - - $referrers = array(); - for ($i = 0; $i < 5; $i++) { - $referrers[] = $this->drupalCreateNode(array( - 'type' => 'page', - 'field_user' => array( - 'und' => array( - array('target_id' => $uid), - ), - ), - ))->nid; - } - - $references = array(); - foreach (user_load($uid, TRUE)->field_node['und'] as $reference) { - $references[] = $reference['target_id']; - } - $this->assertFalse(array_diff($referrers, $references), 'Creating 5 referrers to a single entity creates 5 corresponding references on that entity.', 'CER'); - } - - public function testDuplicateReferencePrevention() { - $uid = $this->drupalCreateUser()->uid; - - $this->drupalCreateNode(array( - 'type' => 'page', - 'field_user' => array( - 'und' => array( - array('target_id' => $uid), - array('target_id' => $uid), - ), - ), - )); - - $account = user_load($uid, TRUE); - $this->assertEqual(sizeof($account->field_node['und']), 1, 'Creating two references to an entity from a single referrer creates one corresponding reference.', 'CER'); - } - - public function testExplicitReferenceCreation() { - $uid = $this->drupalCreateNode()->uid; - - $node = $this->drupalCreateNode(array('type' => 'page')); - $node->field_user['und'][0]['target_id'] = $uid; - node_save($node); - - $account = user_load($uid, TRUE); - $this->assertEqual($account->field_node['und'][0]['target_id'], $node->nid, 'Creating an explicit reference between to unrelated entities creates a corresponding reference.', 'CER'); - } - - public function testExplicitDereference() { - $uid = $this->drupalCreateUser()->uid; - - $nid = $this->drupalCreateNode(array( - 'type' => 'page', - 'field_user' => array( - 'und' => array( - array('target_id' => $uid), - ), - ), - ))->nid; - - $account = user_load($uid, TRUE); - $account->field_node = array(); - user_save($account); - - $node = node_load($nid, NULL, TRUE); - $this->assertFalse($node->field_user, 'Explicitly clearing a reference from the referenced entity clears the corresponding reference on the referrer.', 'CER'); - } - - public function testReferrerDeletion() { - $uid = $this->drupalCreateUser()->uid; - - $referrers = array(); - for ($i = 0; $i < 5; $i++) { - $referrers[] = $this->drupalCreateNode(array( - 'type' => 'page', - 'field_user' => array( - 'und' => array( - array('target_id' => $uid), - ), - ), - ))->nid; - } - - node_delete($referrers[0]); - - $references = array(); - foreach (user_load($uid, TRUE)->field_node['und'] as $reference) { - $references[] = $reference['target_id']; - } - $this->assertFalse(in_array($referrers[0], $references), 'Deleting a referrer clears corresponding reference on the referenced entity.', 'CER'); - } - - public function testReferencedEntityDeletion() { - $uid = $this->drupalCreateUser()->uid; - - $referrers = array(); - for ($i = 0; $i < 5; $i++) { - $referrers[] = $this->drupalCreateNode(array( - 'type' => 'page', - 'field_user' => array( - 'und' => array( - array('target_id' => $uid), - ), - ), - ))->nid; - } - user_delete($uid); - - $cleared = 0; - foreach ($referrers as $nid) { - $node = node_load($nid, NULL, TRUE); - $cleared += (int) empty($node->field_user); - } - $this->assertEqual($cleared, sizeof($referrers), 'Deleting a referenced entity clears all references to it.', 'CER'); - } - -} \ No newline at end of file diff --git a/sites/all/modules/contrib/fields/cer/tests/fields.test b/sites/all/modules/contrib/fields/cer/tests/fields.test deleted file mode 100644 index e117b819..00000000 --- a/sites/all/modules/contrib/fields/cer/tests/fields.test +++ /dev/null @@ -1,67 +0,0 @@ - 'Fields', - 'group' => 'Corresponding Entity Reference', - 'description' => 'Tests integration with the Field API.', - ); - } - - public function setUp() { - parent::setUp('field', 'field_sql_storage', 'ctools', 'entityreference', 'cer'); - - field_create_field(array( - 'field_name' => 'field_user', - 'type' => 'entityreference', - 'cardinality' => -1, - 'settings' => array( - 'target_type' => 'user', - ), - )); - field_create_field(array( - 'field_name' => 'field_node', - 'type' => 'entityreference', - 'cardinality' => -1, - 'settings' => array( - 'target_type' => 'node', - ), - )); - - field_create_instance(array( - 'field_name' => 'field_user', - 'entity_type' => 'node', - 'bundle' => 'page', - )); - field_create_instance(array( - 'field_name' => 'field_node', - 'entity_type' => 'user', - 'bundle' => 'user', - )); - - ctools_include('export'); - - $preset = ctools_export_crud_new('cer'); - $preset->entity_types_content_fields = 'node*page*field_user*user*user*field_node'; - $preset->enabled = TRUE; - - ctools_export_crud_save('cer', $preset); - } - - public function testFieldInstanceDelete() { - field_delete_instance(field_info_instance('user', 'field_node', 'user')); - - $preset = cer_preset_load('node*page*field_user*user*user*field_node'); - $this->assertNull($preset, 'Deleting a field instance clears CER presets for that instance.'); - } - - public function testFieldDelete() { - field_delete_field('field_user'); - - $preset = cer_preset_load('node*page*field_user*user*user*field_node'); - $this->assertNull($preset, 'Deleting a field clears CER presets for that field.'); - } - -} \ No newline at end of file diff --git a/sites/all/modules/contrib/panels/panels/CHANGELOG.txt b/sites/all/modules/contrib/panels/panels/CHANGELOG.txt old mode 100755 new mode 100644 diff --git a/sites/all/modules/contrib/panels/panels/KNOWN_ISSUES.txt b/sites/all/modules/contrib/panels/panels/KNOWN_ISSUES.txt old mode 100755 new mode 100644 diff --git a/sites/all/modules/contrib/panels/panels/LICENSE.txt b/sites/all/modules/contrib/panels/panels/LICENSE.txt old mode 100755 new mode 100644 diff --git a/sites/all/modules/contrib/panels/panels/README.txt b/sites/all/modules/contrib/panels/panels/README.txt old mode 100755 new mode 100644 index 2181b789..3c86762e --- a/sites/all/modules/contrib/panels/panels/README.txt +++ b/sites/all/modules/contrib/panels/panels/README.txt @@ -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 \ No newline at end of file diff --git a/sites/all/modules/contrib/panels/panels/UPGRADE.txt b/sites/all/modules/contrib/panels/panels/UPGRADE.txt old mode 100755 new mode 100644 index d1a42f2a..05c0c989 --- a/sites/all/modules/contrib/panels/panels/UPGRADE.txt +++ b/sites/all/modules/contrib/panels/panels/UPGRADE.txt @@ -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. diff --git a/sites/all/modules/contrib/panels/panels/css/panels-dashboard.css b/sites/all/modules/contrib/panels/panels/css/panels-dashboard.css old mode 100755 new mode 100644 diff --git a/sites/all/modules/contrib/panels/panels/css/panels.css b/sites/all/modules/contrib/panels/panels/css/panels.css old mode 100755 new mode 100644 index 99552a94..13c473cc --- a/sites/all/modules/contrib/panels/panels/css/panels.css +++ b/sites/all/modules/contrib/panels/panels/css/panels.css @@ -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; } diff --git a/sites/all/modules/contrib/panels/panels/css/panels_admin.css b/sites/all/modules/contrib/panels/panels/css/panels_admin.css old mode 100755 new mode 100644 diff --git a/sites/all/modules/contrib/panels/panels/css/panels_dnd.css b/sites/all/modules/contrib/panels/panels/css/panels_dnd.css old mode 100755 new mode 100644 index 530b359d..7252ad67 --- a/sites/all/modules/contrib/panels/panels/css/panels_dnd.css +++ b/sites/all/modules/contrib/panels/panels/css/panels_dnd.css @@ -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 { diff --git a/sites/all/modules/contrib/panels/panels/css/panels_page.css b/sites/all/modules/contrib/panels/panels/css/panels_page.css old mode 100755 new mode 100644 diff --git a/sites/all/modules/contrib/panels/panels/help/api.html b/sites/all/modules/contrib/panels/panels/help/api.html old mode 100755 new mode 100644 diff --git a/sites/all/modules/contrib/panels/panels/help/display.html b/sites/all/modules/contrib/panels/panels/help/display.html old mode 100755 new mode 100644 diff --git a/sites/all/modules/contrib/panels/panels/help/pane.html b/sites/all/modules/contrib/panels/panels/help/pane.html old mode 100755 new mode 100644 diff --git a/sites/all/modules/contrib/panels/panels/help/panels.help.ini b/sites/all/modules/contrib/panels/panels/help/panels.help.ini old mode 100755 new mode 100644 diff --git a/sites/all/modules/contrib/panels/panels/help/plugin-layout.html b/sites/all/modules/contrib/panels/panels/help/plugin-layout.html deleted file mode 100755 index e5c0f5ce..00000000 --- a/sites/all/modules/contrib/panels/panels/help/plugin-layout.html +++ /dev/null @@ -1,80 +0,0 @@ -Layout plugins are one of the simplest and most powerful sections of the panels api. There are two different ways that a layout can be implemented via panels. Panels supports both module and theme implementations of panels. The module implementation requires that hook_ctools_plugin_directory define the directory in which your layout plugins exist. (This same hook defines the directory for all panels plugins) Alternately, if you intend on implementing a layout in a theme this can be done primary through the theme's info file. The Ctools help does a great job of actually explaining this portion of the API ctools: plugins.
- -Ctools explains even the layout hooks a little in its example, but we'll recap quickly and expand on this information. As ctools explains, the actual plugin file must be named with care as it will directly affect your naming scheme for the hook within it. This is really no different from any other hook within drupal except that we'll be using multiple replacements in this case. The function we're looking to implement is an instance of:
-function YOURMODULE_PLUGINNAME_OWNERMODULE_PLUGINTYPE()
-In our case we already know that the function will be:
-function YOURMODULE_PLUGINNAME_panels_layouts()
-This is because the plugin type we're working with is a layout, and the module that implements these layouts is the panels module. For the rest of the naming scheme "YOURMODULE" will be replaced with either the name of your module that implements this layout, or the name of the theme, and "PLUGINNAME" will be replaced with whatever the name of the plugin file is. For purposes of this example our module name us going to be "layout_sample" and our plugin will be "first_layout".
We're going to assume that you've laid your directory structure out very similarly to how panels does it. Something like this is rather likely: -
layout_sample - layout_sample.info - layout_sample.module - plugins - layouts - first_layout - first_layout.css - first_layout.inc - first_layout.png - layout-sample-first-layout.tpl.php-The name of our .inc file is going to be the key to the entire layout plugin. - -
We will start with the first_layout.inc file as it's the most important file we're dealing with here. First_layout.inc will look similar to the following: -
function layout_sample_first_layout_panels_layouts() {
- $items['first_layout'] = array(
- 'title' => t('First Layout'),
- 'icon' => 'first_layout.png',
- 'theme' => 'layout_sample_first_layout',
- 'css' => 'first_layout.css',
- 'panels' => array(
- 'main' => t('Main region'),
- 'right' => t('Right region'),
- ),
- );
- return $items;
-}
-The include file defines all the other files that our layout will utilize in order to be truly useful. The array is fairly self explanitory but for the sake of specificity:
-function layout_sample_first_layout_panels_layouts() {
- $items['first_layout'] = array(
- 'title' => t('First Layout'),
- 'icon' => 'first_layout.png',
- 'theme' => 'layout_sample_first_layout',
- 'css' => 'first_layout.css',
- 'admin css' => 'first_layout_admin.css',
- 'panels' => array(
- 'main' => t('Main region'),
- 'right' => t('Right region'),
- ),
- );
- return $items;
-
-
-
-The tpl.php file is very similar to any other template file within drupal. The difference here is that we're being passed an array of regions through $content, and we also have a css id available to us for the entire panel in the form of $css_id. The template is very straight forward and will look similar to the following: -
<div class="panel-display panel-stacked-twothirds-onethird clearfix" <?php if (!empty($css_id)) { print "id=\"$css_id\""; } ?>>
- <div class="panel-panel panel-col-first panel-region-main">
- <div class="inside"><?php print $content['main']; ?></div>
- </div>
-
- <div class="panel-panel panel-col-last panel-region-right">
- <div class="inside"><?php print $content['right']; ?></div>
- </div>
-</div>
-
-This is simply an example of what the html could look like. You can alter an update this html to fit your own needs.
-
-
-The css and png files are as simple as any other css or png file you've ever utilized. Panels provides some images for its graphical representations of its layouts. I would heavily encourage you to modify these to suit your needs. The CSS files (admin and non) will be included at the appropriate times. Simply set them up to fit your purposes. If you're utilizing fixed width panel regions it's probably smart to provide an admin css file as well with your panel layout.
diff --git a/sites/all/modules/contrib/panels/panels/help/plugins-layout.html b/sites/all/modules/contrib/panels/panels/help/plugins-layout.html old mode 100755 new mode 100644 index 85a33c4b..cbc043d8 --- a/sites/all/modules/contrib/panels/panels/help/plugins-layout.html +++ b/sites/all/modules/contrib/panels/panels/help/plugins-layout.html @@ -1,11 +1,7 @@Layout plugins are one of the simplest and most powerful sections of the panels api. There are two different ways that a layout can be implemented via panels. Panels supports both module and theme implementations of panels. The module implementation requires that hook_ctools_plugin_directory define the directory in which your layout plugins exist. (This same hook defines the directory for all panels plugins) Alternately, if you intend on implementing a layout in a theme this can be done primary through the theme's info file. The CTools help does a great job of actually explaining this portion of the API ctools: plugins.
+Layout plugins are one of the simplest and most powerful sections of the Panels API. There are two different ways that a layout can be implemented via Panels. Panels supports both module and theme implementations of Panels. The module implementation requires that hook_ctools_plugin_directory define the directory in which your layout plugins exist. (This same hook defines the directory for all Panels plugins) Alternately, if you intend on implementing a layout in a theme this can be done primary through the theme's info file. The CTools help does a great job of actually explaining this portion of the API ctools: plugins.
-CTools explains even the layout hooks a little in its example, but we'll recap quickly and expand on this information. As ctools explains, the actual plugin file must be named with care as it will directly affect your naming scheme for the hook within it. This is really no different from any other hook within drupal except that we'll be using multiple replacements in this case. The function we're looking to implement is an instance of:
-function YOURMODULE_PLUGINNAME_OWNERMODULE_PLUGINTYPE()
-In our case we already know that the function will be:
-function YOURMODULE_PLUGINNAME_panels_layouts()
-This is because the plugin type we're working with is a layout, and the module that implements these layouts is the panels module. For the rest of the naming scheme "YOURMODULE" will be replaced with either the name of your module that implements this layout, or the name of the theme, and "PLUGINNAME" will be replaced with whatever the name of the plugin file is. For purposes of this example our module name us going to be "layout_sample" and our plugin will be "first_layout".
For purposes of this example, our module name is going to be "layout_sample" and our plugin will be "first_layout".
We're going to assume that you've laid your directory structure out very similarly to how panels does it. Something like this is rather likely: @@ -21,10 +17,23 @@ This is because the plugin type we're working with is a layout, and the module t layout-sample-first-layout.tpl.php The name of our .inc file is going to be the key to the entire layout plugin.
+First, declare where your custom layouts reside by implementing the CTools hook hook_ctools_plugin_directory():
+
+/**
+ * Implements hook_ctools_plugin_directory().
+ */
+function layout_sample_ctools_plugin_directory($module, $plugin) {
+ if ($module == 'panels' && $plugin == 'layouts') {
+ return 'plugins/layouts';
+ }
+}
+
+
We will start with the first_layout.inc file as it's the most important file we're dealing with here. First_layout.inc will look similar to the following:
- $plugin = array(
+ $plugin = array(
'title' => t('First Layout'),
'icon' => 'first_layout.png',
'theme' => 'layout_sample_first_layout',
@@ -35,15 +44,15 @@ The name of our .inc file is going to be the key to the entire layout plugin.
-The include file defines all the other files that our layout will utilize in order to be truly useful. The array is fairly self explanitory but for the sake of specificity:
+The include file defines all the other files that our layout will utilize in order to be truly useful. The array is fairly self explanitory but for the sake of specificity:
- Title:
The title of our layout. (Utilized within the panels administration screens)
- Icon:
The graphical representation of our layout. (Utilized within the panels administration screens)
-- Theme:
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.)
+- Theme:
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.)
- CSS:
The css file to be utilized for our layout. (Utilized within the panels administration screens, AND when viewing the actual panel itself.)
-- Panels:
Defines all the various regions within your panel. This will be further utilized within our tpl.php file.
+- Panels:
Defines all the various regions within your panel. This will be further utilized within our tpl.php file.
-There are many additional properties that can be added to the include file. For purposes of this document we'll also make mention of the 'admin css' property. 'Admin css' is especially useful when utilizing a fixed width layout with fixed with panel regions. This can break under most administrative circumstances, and panels provides you with the ability to give an additional css layout for the administrative section. It's a simple nicety and looks like this:
+There are many additional properties that can be added to the include file. For purposes of this document we'll also make mention of the 'admin css' property. 'Admin css' is especially useful when utilizing a fixed width layout with fixed with panel regions. This can break under most administrative circumstances, and panels provides you with the ability to give an additional css layout for the administrative section. It's a simple nicety and looks like this:
$plugin = array(
'title' => t('First Layout'),
@@ -60,8 +69,8 @@ There are many additional properties that can be added to the include file. For
The tpl.php File:
-The tpl.php file is very similar to any other template file within drupal. The difference here is that we're being passed an array of regions through $content, and we also have a css id available to us for the entire panel in the form of $css_id. The template is very straight forward and will look similar to the following:
-
<div class="panel-display panel-stacked-twothirds-onethird clearfix" <?php if (!empty($css_id)) { print "id=\"$css_id\""; } ?>>
+The tpl.php file is very similar to any other template file within drupal. The difference here is that we're being passed an array of regions through $content, and we also have a css id available to us for the entire panel in the form of $css_id. The template is very straight forward and will look similar to the following:
+
<div class="panel-display panel-stacked-twothirds-onethird clearfix" <?php if (!empty($css_id)) { print "id=\"$css_id\""; } ?>>
<div class="panel-panel panel-col-first panel-region-main">
<div class="inside"><?php print $content['main']; ?></div>
</div>
@@ -75,4 +84,4 @@ This is simply an example of what the html could look like. You can alter an upd
The Other Files:
-The css and png files are as simple as any other css or png file you've ever utilized. Panels provides some images for its graphical representations of its layouts. I would heavily encourage you to modify these to suit your needs. The CSS files (admin and non) will be included at the appropriate times. Simply set them up to fit your purposes. If you're utilizing fixed width panel regions it's probably smart to provide an admin css file as well with your panel layout.
+The css and png files are as simple as any other css or png file you've ever utilized. Panels provides some images for its graphical representations of its layouts. I would heavily encourage you to modify these to suit your needs. The CSS files (admin and non) will be included at the appropriate times. Simply set them up to fit your purposes. If you're utilizing fixed width panel regions it's probably smart to provide an admin css file as well with your panel layout.
diff --git a/sites/all/modules/contrib/panels/panels/help/plugins-style.html b/sites/all/modules/contrib/panels/panels/help/plugins-style.html
old mode 100755
new mode 100644
diff --git a/sites/all/modules/contrib/panels/panels/i18n_panels/README.txt b/sites/all/modules/contrib/panels/panels/i18n_panels/README.txt
new file mode 100644
index 00000000..71c4b8f9
--- /dev/null
+++ b/sites/all/modules/contrib/panels/panels/i18n_panels/README.txt
@@ -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']),
+ );
+}
diff --git a/sites/all/modules/contrib/panels/panels/i18n_panels/i18n_panels.i18n.inc b/sites/all/modules/contrib/panels/panels/i18n_panels/i18n_panels.i18n.inc
new file mode 100644
index 00000000..71fdafb7
--- /dev/null
+++ b/sites/all/modules/contrib/panels/panels/i18n_panels/i18n_panels.i18n.inc
@@ -0,0 +1,50 @@
+ 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;
+}
diff --git a/sites/all/modules/contrib/panels/panels/i18n_panels/i18n_panels.info b/sites/all/modules/contrib/panels/panels/i18n_panels/i18n_panels.info
new file mode 100644
index 00000000..51a9e374
--- /dev/null
+++ b/sites/all/modules/contrib/panels/panels/i18n_panels/i18n_panels.info
@@ -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-10-16
+version = "7.x-3.8"
+core = "7.x"
+project = "panels"
+datestamp = "1476582295"
+
diff --git a/sites/all/modules/contrib/panels/panels/i18n_panels/i18n_panels.install b/sites/all/modules/contrib/panels/panels/i18n_panels/i18n_panels.install
new file mode 100644
index 00000000..ff7631b8
--- /dev/null
+++ b/sites/all/modules/contrib/panels/panels/i18n_panels/i18n_panels.install
@@ -0,0 +1,27 @@
+ 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;
+}
diff --git a/sites/all/modules/contrib/panels/panels/i18n_panels/i18n_panels.module b/sites/all/modules/contrib/panels/panels/i18n_panels/i18n_panels.module
new file mode 100644
index 00000000..91524e3d
--- /dev/null
+++ b/sites/all/modules/contrib/panels/panels/i18n_panels/i18n_panels.module
@@ -0,0 +1,442 @@
+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 string refresh 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;
+}
diff --git a/sites/all/modules/contrib/panels/panels/images/arrow-active.png b/sites/all/modules/contrib/panels/panels/images/arrow-active.png
old mode 100755
new mode 100644
diff --git a/sites/all/modules/contrib/panels/panels/images/arrow-down-light.png b/sites/all/modules/contrib/panels/panels/images/arrow-down-light.png
old mode 100755
new mode 100644
diff --git a/sites/all/modules/contrib/panels/panels/images/bg-content-modal.png b/sites/all/modules/contrib/panels/panels/images/bg-content-modal.png
old mode 100755
new mode 100644
diff --git a/sites/all/modules/contrib/panels/panels/images/bg-shade-dark.png b/sites/all/modules/contrib/panels/panels/images/bg-shade-dark.png
old mode 100755
new mode 100644
diff --git a/sites/all/modules/contrib/panels/panels/images/bg-shade-light.png b/sites/all/modules/contrib/panels/panels/images/bg-shade-light.png
old mode 100755
new mode 100644
diff --git a/sites/all/modules/contrib/panels/panels/images/bg-shade-medium.png b/sites/all/modules/contrib/panels/panels/images/bg-shade-medium.png
old mode 100755
new mode 100644
diff --git a/sites/all/modules/contrib/panels/panels/images/bg-shade-white-lrg.png b/sites/all/modules/contrib/panels/panels/images/bg-shade-white-lrg.png
old mode 100755
new mode 100644
diff --git a/sites/all/modules/contrib/panels/panels/images/blank.gif b/sites/all/modules/contrib/panels/panels/images/blank.gif
old mode 100755
new mode 100644
diff --git a/sites/all/modules/contrib/panels/panels/images/close.gif b/sites/all/modules/contrib/panels/panels/images/close.gif
old mode 100755
new mode 100644
diff --git a/sites/all/modules/contrib/panels/panels/images/delete.png b/sites/all/modules/contrib/panels/panels/images/delete.png
old mode 100755
new mode 100644
diff --git a/sites/all/modules/contrib/panels/panels/images/go-down.png b/sites/all/modules/contrib/panels/panels/images/go-down.png
old mode 100755
new mode 100644
diff --git a/sites/all/modules/contrib/panels/panels/images/go-right.png b/sites/all/modules/contrib/panels/panels/images/go-right.png
old mode 100755
new mode 100644
diff --git a/sites/all/modules/contrib/panels/panels/images/go-up.png b/sites/all/modules/contrib/panels/panels/images/go-up.png
old mode 100755
new mode 100644
diff --git a/sites/all/modules/contrib/panels/panels/images/icon-addcontent.png b/sites/all/modules/contrib/panels/panels/images/icon-addcontent.png
old mode 100755
new mode 100644
diff --git a/sites/all/modules/contrib/panels/panels/images/icon-cache.png b/sites/all/modules/contrib/panels/panels/images/icon-cache.png
old mode 100755
new mode 100644
diff --git a/sites/all/modules/contrib/panels/panels/images/icon-configure.png b/sites/all/modules/contrib/panels/panels/images/icon-configure.png
old mode 100755
new mode 100644
diff --git a/sites/all/modules/contrib/panels/panels/images/icon-delete.png b/sites/all/modules/contrib/panels/panels/images/icon-delete.png
old mode 100755
new mode 100644
diff --git a/sites/all/modules/contrib/panels/panels/images/icon-draggable.png b/sites/all/modules/contrib/panels/panels/images/icon-draggable.png
old mode 100755
new mode 100644
diff --git a/sites/all/modules/contrib/panels/panels/images/icon-hidepane.png b/sites/all/modules/contrib/panels/panels/images/icon-hidepane.png
old mode 100755
new mode 100644
diff --git a/sites/all/modules/contrib/panels/panels/images/icon-showpane.png b/sites/all/modules/contrib/panels/panels/images/icon-showpane.png
old mode 100755
new mode 100644
diff --git a/sites/all/modules/contrib/panels/panels/images/no-icon.png b/sites/all/modules/contrib/panels/panels/images/no-icon.png
old mode 100755
new mode 100644
diff --git a/sites/all/modules/contrib/panels/panels/images/portlet-collapsed.png b/sites/all/modules/contrib/panels/panels/images/portlet-collapsed.png
old mode 100755
new mode 100644
diff --git a/sites/all/modules/contrib/panels/panels/images/portlet-expanded.png b/sites/all/modules/contrib/panels/panels/images/portlet-expanded.png
old mode 100755
new mode 100644
diff --git a/sites/all/modules/contrib/panels/panels/images/screenshot-1.jpg b/sites/all/modules/contrib/panels/panels/images/screenshot-1.jpg
old mode 100755
new mode 100644
diff --git a/sites/all/modules/contrib/panels/panels/images/screenshot-2.jpg b/sites/all/modules/contrib/panels/panels/images/screenshot-2.jpg
old mode 100755
new mode 100644
diff --git a/sites/all/modules/contrib/panels/panels/images/screenshot-3.jpg b/sites/all/modules/contrib/panels/panels/images/screenshot-3.jpg
old mode 100755
new mode 100644
diff --git a/sites/all/modules/contrib/panels/panels/images/screenshot-4.jpg b/sites/all/modules/contrib/panels/panels/images/screenshot-4.jpg
old mode 100755
new mode 100644
diff --git a/sites/all/modules/contrib/panels/panels/images/sky.png b/sites/all/modules/contrib/panels/panels/images/sky.png
old mode 100755
new mode 100644
diff --git a/sites/all/modules/contrib/panels/panels/images/sprite.png b/sites/all/modules/contrib/panels/panels/images/sprite.png
old mode 100755
new mode 100644
diff --git a/sites/all/modules/contrib/panels/panels/images/throbber.gif b/sites/all/modules/contrib/panels/panels/images/throbber.gif
old mode 100755
new mode 100644
diff --git a/sites/all/modules/contrib/panels/panels/images/user-trash.png b/sites/all/modules/contrib/panels/panels/images/user-trash.png
old mode 100755
new mode 100644
diff --git a/sites/all/modules/contrib/panels/panels/includes/add-content.inc b/sites/all/modules/contrib/panels/panels/includes/add-content.inc
new file mode 100644
index 00000000..5ff1b246
--- /dev/null
+++ b/sites/all/modules/contrib/panels/panels/includes/add-content.inc
@@ -0,0 +1,88 @@
+ $category_info) {
+ // 'root' category is actually displayed under the categories, so
+ // skip it.
+ if ($key == 'root') {
+ continue;
+ }
+
+ $class = 'panels-modal-add-category';
+ if ($key == $vars['category']) {
+ $class .= ' active';
+ }
+
+ $url = $vars['renderer']->get_url('select-content', $vars['region'], $key);
+ $vars['categories_array'][] = ctools_ajax_text_button($category_info['title'], $url, '', $class);
+ }
+
+ // Now render the top level buttons (aka the root category) if any.
+ $vars['root_content'] = '';
+ if (!empty($vars['categories']['root'])) {
+ foreach ($vars['categories']['root']['content'] as $content_type) {
+ $vars['root_content'] .= theme('panels_add_content_link', array('renderer' => $vars['renderer'], 'region' => $vars['region'], 'content_type' => $content_type));
+ }
+ }
+}
+
+/**
+ * Process the panels add content modal.
+ *
+ * This is run here so that preprocess can make changes before links are
+ * actually rendered.
+ */
+function template_process_panels_add_content_modal(&$vars) {
+ $content = !empty($vars['categories'][$vars['category']]['content']) ? $vars['categories'][$vars['category']]['content'] : array();
+
+ // If no category is selected or the category is empty or our special empty
+ // category render a 'header' that will appear instead of the columns.
+ if (empty($vars['category']) || empty($content) || $vars['category'] == 'root') {
+ $vars['header'] = t('Content options are divided by category. Please select a category from the left to proceed.');
+ }
+ else {
+ $titles = array_keys($content);
+ natcasesort($titles);
+
+ // This will default to 2 columns in the theme definition but could be
+ // changed by a preprocess. Ensure there is at least one column.
+ $columns = max(1, $vars['column_count']);
+ $vars['columns'] = array_fill(1, $columns, '');
+
+ $col_size = count($titles) / $columns;
+ $count = 0;
+ foreach ($titles as $title) {
+ $which = floor($count++ / $col_size) + 1;
+ $vars['columns'][$which] .= theme('panels_add_content_link', array('renderer' => $vars['renderer'], 'region' => $vars['region'], 'content_type' => $content[$title]));
+ }
+ }
+
+ $vars['messages'] = theme('status_messages');
+}
+
+/**
+ * Preprocess the add content link used in the modal.
+ */
+function template_preprocess_panels_add_content_link(&$vars) {
+ $vars['title'] = filter_xss_admin($vars['content_type']['title']);
+ $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']);
+ $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');
+ }
+}
diff --git a/sites/all/modules/contrib/panels/panels/includes/callbacks.inc b/sites/all/modules/contrib/panels/panels/includes/callbacks.inc
old mode 100755
new mode 100644
index 5188394e..255a3cdd
--- a/sites/all/modules/contrib/panels/panels/includes/callbacks.inc
+++ b/sites/all/modules/contrib/panels/panels/includes/callbacks.inc
@@ -172,6 +172,22 @@ function panels_admin_settings_page() {
}
}
+ ctools_include('plugins', 'panels');
+ $pipelines = panels_get_renderer_pipelines();
+ $options = array();
+ foreach ($pipelines as $key => $value) {
+ $options[$key] = $value->admin_title;
+ }
+ if (count($options) > 1) {
+ $form['panels_renderer_default'] = array(
+ '#type' => 'select',
+ '#title' => t('Default renderer'),
+ '#options' => $options,
+ '#default_value' => variable_get('panels_renderer_default', 'standard'),
+ '#description' => t('The default renderer for new panel pages.'),
+ );
+ }
+
if (empty($form)) {
return array('#value' => t('There are currently no settings to change, but additional plugins or modules may provide them in the future.'));
}
diff --git a/sites/all/modules/contrib/panels/panels/includes/common.inc b/sites/all/modules/contrib/panels/panels/includes/common.inc
old mode 100755
new mode 100644
index bd90f667..9e150e31
--- a/sites/all/modules/contrib/panels/panels/includes/common.inc
+++ b/sites/all/modules/contrib/panels/panels/includes/common.inc
@@ -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;
@@ -196,7 +196,7 @@ class panels_allowed_layouts {
*/
function save() {
if (!is_null($this->module_name)) {
- variable_set($this->module_name . "_allowed_layouts", serialize($this));
+ variable_set($this->module_name . '_allowed_layouts', serialize($this));
}
}
@@ -245,9 +245,19 @@ function panels_common_settings($form, &$form_state, $module_name = 'panels_comm
}
$default_options['other'] = t('New content of other types');
- $form['panels_common_default'] = array(
- '#type' => 'checkboxes',
+
+ $form['additional_settings'] = array(
+ '#type' => 'vertical_tabs',
+ );
+
+ $form['common'] = array(
+ '#type' => 'fieldset',
'#title' => t('New content behavior'),
+ '#group' => 'additional_settings',
+ '#weight' => -10,
+ );
+ $form['common']['panels_common_default'] = array(
+ '#type' => 'checkboxes',
'#description' => t('Select the default behavior of new content added to the system. If checked, new content will automatically be immediately available to be added to Panels pages. If not checked, new content will not be available until specifically allowed here.'),
'#options' => $default_options,
'#default_value' => array_keys(array_filter($default_types)),
@@ -262,7 +272,11 @@ function panels_common_settings($form, &$form_state, $module_name = 'panels_comm
// each type its own checkboxes set unless it's 'single' in which
// case it can go into our fake other set.
$available_content_types = ctools_content_get_all_types();
- $allowed_content_types = variable_get($module_name . '_allowed_types', array());
+ $allowed_content_types = db_select('panels_allowed_types', 'pat')
+ ->fields('pat', array('type', 'allowed'))
+ ->condition('module', $module_name)
+ ->execute()
+ ->fetchAllKeyed();
foreach ($available_content_types as $id => $types) {
foreach ($types as $type => $info) {
@@ -280,18 +294,23 @@ function panels_common_settings($form, &$form_state, $module_name = 'panels_comm
$form['content_types'] = array(
'#tree' => TRUE,
- '#prefix' => '',
- '#suffix' => '',
);
+
// cheat a bit
$content_types['other'] = array('title' => t('Other'), 'weight' => 10);
foreach ($content_types as $id => $info) {
if (isset($allowed[$id])) {
+
$form['content_types'][$id] = array(
+ '#type' => 'fieldset',
+ '#group' => 'additional_settings',
+ '#title' => t('Allowed @s content', array('@s' => $info['title'])),
+ );
+
+ $form['content_types'][$id]['options'] = array(
'#prefix' => '',
'#suffix' => '',
'#type' => 'checkboxes',
- '#title' => t('Allowed @s content', array('@s' => $info['title'])),
'#options' => $options[$id],
'#default_value' => array_keys(array_filter($allowed[$id])),
'#checkall' => TRUE,
@@ -300,8 +319,14 @@ function panels_common_settings($form, &$form_state, $module_name = 'panels_comm
}
}
+ // Layout selection.
panels_common_allowed_layouts_form($form, $form_state, $module_name);
+ $form['allowed'] = array(
+ '#type' => 'value',
+ '#value' => isset($allowed) ? array_keys($allowed) : array(),
+ );
+
$form['module_name'] = array(
'#type' => 'value',
'#value' => $module_name,
@@ -331,8 +356,23 @@ 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
- variable_set($module_name . '_allowed_types', call_user_func_array('array_merge', $form_state['values']['content_types']));
+ // Merge the broken apart array neatly back together.
+ $allowed_content_types = array();
+ $content_types = $form_state['values']['allowed'];
+ foreach ($content_types as $content_type) {
+ $allowed_content_types = array_merge($allowed_content_types, $form_state['values']['content_types'][$content_type]['options']);
+ foreach ($allowed_content_types as $type => $allowed) {
+ $allowed = empty($allowed) ? 0 : 1;
+ db_merge('panels_allowed_types')
+ ->key(array('module' => $module_name, 'type' => $type))
+ ->fields(array(
+ 'module' => $module_name,
+ 'type' => $type,
+ 'allowed' => $allowed,
+ ))
+ ->execute();
+ }
+ }
}
drupal_set_message(t('Your changes have been saved.'));
}
@@ -342,9 +382,13 @@ function panels_common_settings_submit($form, &$form_state) {
*/
function panels_common_get_allowed_types($module, $contexts = array(), $has_content = FALSE, $default_defaults = array(), $default_allowed_types = array()) {
// Get a list of all types that are available
-
$default_types = variable_get($module . '_default', $default_defaults);
- $allowed_types = variable_get($module . '_allowed_types', $default_allowed_types);
+ $allowed_types = db_select('panels_allowed_types', 'pat')
+ ->fields('pat', array('type', 'allowed'))
+ ->condition('module', $module)
+ ->execute()
+ ->fetchAllKeyed();
+ $allowed_types = !empty($allowed_types) ? $allowed_types : $default_allowed_types;
// By default, if they haven't gone and done the initial setup here,
// let all 'other' types (which will be all types) be available.
@@ -391,9 +435,15 @@ function panels_common_allowed_layouts_form(&$form, &$form_state, $module_name)
$form_state['allowed_layouts'] = &$allowed_layouts;
ctools_add_js('layout', 'panels');
- $form['layouts'] = array(
- '#type' => 'checkboxes',
+
+ $form['layout_selection'] = array(
+ '#type' => 'fieldset',
'#title' => t('Select allowed layouts'),
+ '#group' => 'additional_settings',
+ '#weight' => 10,
+ );
+ $form['layout_selection']['layouts'] = array(
+ '#type' => 'checkboxes',
'#options' => $options,
'#description' => t('Check the boxes for all layouts you want to allow users choose from when picking a layout. You must allow at least one layout.'),
'#default_value' => array_keys(array_filter($allowed_layouts->allowed_layout_settings)),
@@ -423,7 +473,7 @@ function panels_common_allowed_layouts_form_submit($form, &$form_state) {
* Get the allowed layout object for the given module.
*/
function panels_common_get_allowed_layout_object($module_name) {
- $allowed_layouts = unserialize(variable_get($module_name . "_allowed_layouts", serialize('')));
+ $allowed_layouts = unserialize(variable_get($module_name . '_allowed_layouts', serialize('')));
// if no parameter was provided, or the variable_get failed
if (!$allowed_layouts) {
@@ -445,6 +495,7 @@ function panels_common_get_allowed_layout_object($module_name) {
* Get the allowed layouts for the given module.
*/
function panels_common_get_allowed_layouts($module_name) {
+ ctools_include('plugins', 'panels');
$available_layouts = panels_get_layouts();
if (empty($module_name)) {
return $available_layouts;
@@ -516,16 +567,21 @@ function theme_panels_common_content_list($vars) {
* @return
* The rendered output.
*/
-function panels_common_print_layout_links($layouts, $base_path, $link_options = array()) {
+function panels_common_print_layout_links($layouts, $base_path, $link_options = array(), $current_layout = NULL) {
$output = '';
$categories = array();
ctools_include('cleanstring');
+ $default_category = '';
foreach ($layouts as $id => $layout) {
$category = ctools_cleanstring($layout['category']);
$categories[$category] = $layout['category'];
- $options[$category][$id] = panels_print_layout_link($id, $layout, $base_path . '/' . $id, $link_options);
+ if ($id == $current_layout) {
+ $default_category = $category;
+ }
+
+ $options[$category][$id] = panels_print_layout_link($id, $layout, $base_path . '/' . $id, $link_options, $current_layout);
}
$form = array();
@@ -535,8 +591,9 @@ function panels_common_print_layout_links($layouts, $base_path, $link_options =
'#options' => $categories,
'#name' => 'categories',
'#id' => 'edit-categories',
- '#value' => '',
+ '#value' => $default_category,
'#parents' => array('categories'),
+ '#access' => (count($categories) > 1) ? TRUE : FALSE,
);
$output .= drupal_render($form);
@@ -557,7 +614,7 @@ function panels_common_print_layout_links($layouts, $base_path, $link_options =
$output .= '';
$output .= '';
- $output .= '' . $categories[$category] . '';
+ $output .= (count($categories) > 1) ? '' . $categories[$category] . '' : '';
foreach ($links as $key => $link) {
$output .= $link;
diff --git a/sites/all/modules/contrib/panels/panels/includes/display-edit.inc b/sites/all/modules/contrib/panels/panels/includes/display-edit.inc
old mode 100755
new mode 100644
index 7d00d6b5..dbc4786c
--- a/sites/all/modules/contrib/panels/panels/includes/display-edit.inc
+++ b/sites/all/modules/contrib/panels/panels/includes/display-edit.inc
@@ -68,6 +68,7 @@ function panels_edit_display_form($form, &$form_state) {
$links = $renderer->get_display_links();
}
else {
+ $renderer->no_edit_links = TRUE;
$links = '';
}
$form['hide']['display-settings'] = array(
@@ -239,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,
@@ -301,7 +302,7 @@ function panels_edit_display_settings_form($form, &$form_state) {
* Validate the layout settings form.
*/
function panels_edit_display_settings_form_validate($form, &$form_state) {
- if ($function = panels_plugin_get_function('layout', $form_state['layout'], 'settings validate')) {
+ if ($function = panels_plugin_get_function('layouts', $form_state['layout'], 'settings validate')) {
$function($form_state['values']['layout_settings'], $form['layout_settings'], $form_state['display'], $form_state['layout'], $form_state['display']->layout_settings);
}
}
@@ -311,7 +312,7 @@ function panels_edit_display_settings_form_validate($form, &$form_state) {
*/
function panels_edit_display_settings_form_submit($form, &$form_state) {
$display = &$form_state['display'];
- if ($function = panels_plugin_get_function('layout', $form_state['layout'], 'settings submit')) {
+ if ($function = panels_plugin_get_function('layouts', $form_state['layout'], 'settings submit')) {
$function($form_state['values']['layout_settings'], $display, $form_state['layout'], $display->layout_settings);
}
diff --git a/sites/all/modules/contrib/panels/panels/includes/display-layout.inc b/sites/all/modules/contrib/panels/panels/includes/display-layout.inc
old mode 100755
new mode 100644
index fb027989..a21e6630
--- a/sites/all/modules/contrib/panels/panels/includes/display-layout.inc
+++ b/sites/all/modules/contrib/panels/panels/includes/display-layout.inc
@@ -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(
@@ -125,6 +126,10 @@ function panels_choose_layout($form, &$form_state) {
);
foreach ($radios as $key => $choice) {
+ // Set the first available layout as default value.
+ if (empty($display->layout)) {
+ $display->layout = $key;
+ }
// Generate the parents as the autogenerator does, so we will have a
// unique id for each radio button.
$form['layout'][$category][$key] = array(
@@ -176,16 +181,54 @@ function panels_choose_layout_submit($form, &$form_state) {
* The Drupal $form_state
*/
function panels_change_layout($form, &$form_state) {
- $display = &$form_state['display'];
+ // Provide a temporary display and renderer.
+ $form_state['layout_display'] = $display = panels_new_display();
+ if (isset($form_state['cache_key'])) {
+ $display->cache_key = $form_state['cache_key'];
+ }
$new_layout = panels_get_layout($form_state['layout']);
- $new_layout_panels = panels_get_regions($new_layout, $display);
+ $new_layout_regions = panels_get_regions($new_layout, $display);
- $options = $new_layout_panels;
- $keys = array_keys($options);
- $default = current($options);
+ $old_layout = panels_get_layout($form_state['display']->layout);
+ $old_layout_regions = panels_get_regions($old_layout, $form_state['display']);
- $old_layout = panels_get_layout($display->layout);
+ $display->layout = $form_state['layout'];
+ $renderer = panels_get_renderer_handler('editor', $display);
+
+ $renderer->meta_location = 'inline';
+
+ ctools_add_css('panels_admin', 'panels');
+ ctools_add_css('panels_dnd', 'panels');
+ ctools_add_css('dropdown');
+
+ // For every region that had content in the old layout, create a custom pane
+ // in the new layout that represents that region.
+ $keys = array_keys($new_layout_regions);
+ $default_region = reset($keys);
+ foreach ($old_layout_regions as $region_id => $region_name) {
+ if (!empty($form_state['display']->panels[$region_id])) {
+ $pane = panels_new_pane('custom', 'custom', TRUE);
+ $pane->pid = $region_id;
+ $pane->configuration['title'] = t('Panes');
+ $pane->configuration['admin_title'] = $region_name;
+ // Get a list of pane titles used.
+ $titles = array();
+ foreach ($form_state['display']->panels[$region_id] as $pid) {
+ $content_type = ctools_get_content_type($form_state['display']->content[$pid]->type);
+ $titles[$pid] = ctools_content_admin_title($content_type, $form_state['display']->content[$pid]->subtype, $form_state['display']->content[$pid]->configuration, $form_state['display']->context);
+ }
+ $pane->configuration['body'] = '- ' . implode('
- ', $titles) . '
';
+
+ // If the region id matches, make it the same; otherwise, put it
+ // in the default region.
+ $pane->panel = empty($new_layout_regions[$region_id]) ? $default_region : $region_id;
+
+ // Add the pane to the approprate spots.
+ $display->content[$pane->pid] = $pane;
+ $display->panels[$pane->panel][] = $pane->pid;
+ }
+ }
$form['container'] = array(
'#prefix' => '',
@@ -193,7 +236,7 @@ function panels_change_layout($form, &$form_state) {
);
$form['container']['old_layout'] = array(
- '#markup' => panels_print_layout_icon($display->layout, $old_layout, check_plain($old_layout['title'])),
+ '#markup' => panels_print_layout_icon($form_state['display']->layout, $old_layout, check_plain($old_layout['title'])),
);
$form['container']['right_arrow'] = array(
@@ -203,29 +246,17 @@ function panels_change_layout($form, &$form_state) {
'#markup' => panels_print_layout_icon($form_state['layout'], $new_layout, check_plain($new_layout['title'])),
);
- $form['old'] = array(
- '#tree' => true,
- '#prefix' => '',
- '#suffix' => '',
+ $edit_form_state = array(
+ 'display' => $display,
+ 'renderer' => $renderer,
+ 'no buttons' => TRUE,
+ 'no preview' => TRUE,
+ 'no display settings' => TRUE,
+ 'display_title' => '',
);
- $old_layout_panels = panels_get_regions($old_layout, $display);
- if (empty($display->panels)) {
- $form['old'] = array(
- '#prefix' => '',
- '#markup' => t('There is no content in the panel display. If there were content, you would be given an opportunity to select where in the new layout the old content would be placed. Select "Save" or "Continue" to proceed. This change will not be processed if you do not continue.'),
- '#suffix' => '',
- );
- }
-
- foreach ($display->panels as $id => $content) {
- $form['old'][$id] = array(
- '#type' => 'select',
- '#title' => t('Move content in @layout to', array('@layout' => $old_layout_panels[$id])),
- '#options' => $options,
- '#default_value' => array_key_exists($id, $options) ? $id : $default,
- );
- }
+ ctools_include('display-edit', 'panels');
+ $form = panels_edit_display_form($form, $edit_form_state);
if (empty($form_state['no buttons'])) {
$form['back'] = array(
@@ -250,25 +281,48 @@ function panels_change_layout($form, &$form_state) {
* This submit handler will move panes around and save the display.
*/
function panels_change_layout_submit($form, &$form_state) {
- $display = &$form_state['display'];
+ $display = $form_state['display'];
+ $layout_display = $form_state['layout_display'];
- if (!empty($form_state['values']['old'])) {
- foreach ($form_state['values']['old'] as $id => $new_id) {
- if (isset($display->panels[$id])) {
- if (!isset($content[$new_id])) {
- $content[$new_id] = array();
+ $switch = array();
+
+ // Calculate the pids submitted by the display and make a list of
+ // translation to the regions. Remember the 'pid' of the pane
+ // is the region id in the old layout.
+ if (!empty($form_state['values']['panel']['pane'])) {
+ foreach ($form_state['values']['panel']['pane'] as $region_id => $panes) {
+ if ($panes) {
+ $pids = explode(',', $panes);
+ // need to filter the array, b/c passing it in a hidden field can generate trash
+ foreach (array_filter($pids) as $pid) {
+ $switch[$pid] = $region_id;
}
- $content[$new_id] = array_merge($content[$new_id], $display->panels[$id]);
- }
- foreach ($content[$new_id] as $pid) {
- $display->content[$pid]->panel = $new_id;
}
}
-
- $display->panels = $content;
}
+ $content = array();
+ foreach ($switch as $region_id => $new_region_id) {
+ if (isset($display->panels[$region_id])) {
+ if (!isset($content[$new_region_id])) {
+ $content[$new_region_id] = array();
+ }
+ $content[$new_region_id] = array_merge($content[$new_region_id], $display->panels[$region_id]);
+ }
+ }
+
+ // Go through each pane and make sure its region id is correct.
+ foreach ($content as $region_id => $region) {
+ foreach ($region as $pid) {
+ $display->content[$pid]->panel = $region_id;
+ }
+ }
+
+ $display->panels = $content;
+
$display->layout = $form_state['layout'];
+
+ panels_edit_display_settings_form_submit($form, $form_state);
}
/**
diff --git a/sites/all/modules/contrib/panels/panels/includes/legacy.inc b/sites/all/modules/contrib/panels/panels/includes/legacy.inc
old mode 100755
new mode 100644
diff --git a/sites/all/modules/contrib/panels/panels/includes/page-wizard.inc b/sites/all/modules/contrib/panels/panels/includes/page-wizard.inc
old mode 100755
new mode 100644
diff --git a/sites/all/modules/contrib/panels/panels/includes/panels.pipelines.inc b/sites/all/modules/contrib/panels/panels/includes/panels.pipelines.inc
old mode 100755
new mode 100644
diff --git a/sites/all/modules/contrib/panels/panels/includes/plugins.inc b/sites/all/modules/contrib/panels/panels/includes/plugins.inc
old mode 100755
new mode 100644
index 089d9014..be5cd257
--- a/sites/all/modules/contrib/panels/panels/includes/plugins.inc
+++ b/sites/all/modules/contrib/panels/panels/includes/plugins.inc
@@ -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,22 +173,43 @@ 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:
$tokens = ctools_set_page_token();
foreach ($this->tokens as $token => $argument) {
if (isset($tokens[$token])) {
- unset($tokens);
+ unset($tokens[$token]);
}
}
@@ -209,11 +230,11 @@ class panels_cache_object {
}
if (!empty($this->js)) {
foreach ($this->js as $key => $args) {
- if ($key != 'settings') {
+ if ($key !== 'settings') {
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.
*
diff --git a/sites/all/modules/contrib/panels/panels/js/display_editor.js b/sites/all/modules/contrib/panels/panels/js/display_editor.js
old mode 100755
new mode 100644
index d873c9d3..53274f68
--- a/sites/all/modules/contrib/panels/panels/js/display_editor.js
+++ b/sites/all/modules/contrib/panels/panels/js/display_editor.js
@@ -16,7 +16,7 @@ Drupal.Panels.bindClickDelete = function(context) {
$('a.pane-delete:not(.pane-delete-processed)', context)
.addClass('pane-delete-processed')
.click(function() {
- if (confirm('Remove this pane?')) {
+ if (confirm(Drupal.t('Remove this pane?'))) {
var id = '#' + $(this).attr('id').replace('pane-delete-', '');
$(id).remove();
Drupal.Panels.Draggable.savePositions();
@@ -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');
diff --git a/sites/all/modules/contrib/panels/panels/js/layout.js b/sites/all/modules/contrib/panels/panels/js/layout.js
old mode 100755
new mode 100644
diff --git a/sites/all/modules/contrib/panels/panels/js/panels-base.js b/sites/all/modules/contrib/panels/panels/js/panels-base.js
old mode 100755
new mode 100644
index 7b0b9223..31eb010e
--- a/sites/all/modules/contrib/panels/panels/js/panels-base.js
+++ b/sites/all/modules/contrib/panels/panels/js/panels-base.js
@@ -4,7 +4,7 @@
*/
(function ($) {
- Drupal.Panels = {}
+ Drupal.Panels = Drupal.Panels || {};
Drupal.Panels.changed = function(item) {
if (!item.is('.changed')) {
@@ -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.
diff --git a/sites/all/modules/contrib/panels/panels/js/panels.js b/sites/all/modules/contrib/panels/panels/js/panels.js
deleted file mode 100755
index 70e8544c..00000000
--- a/sites/all/modules/contrib/panels/panels/js/panels.js
+++ /dev/null
@@ -1,28 +0,0 @@
-
-(function ($) {
- 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);
diff --git a/sites/all/modules/contrib/panels/panels/panels.api.php b/sites/all/modules/contrib/panels/panels/panels.api.php
new file mode 100644
index 00000000..1aa1c6ad
--- /dev/null
+++ b/sites/all/modules/contrib/panels/panels/panels.api.php
@@ -0,0 +1,264 @@
+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);
+}
diff --git a/sites/all/modules/contrib/panels/panels/panels.info b/sites/all/modules/contrib/panels/panels/panels.info
old mode 100755
new mode 100644
index ef741367..6a6f29fe
--- a/sites/all/modules/contrib/panels/panels/panels.info
+++ b/sites/all/modules/contrib/panels/panels/panels.info
@@ -10,9 +10,17 @@ 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 2012-01-18
-version = "7.x-3.0"
+; Tests.
+; Task handlers for entities. These inherit off one base class to make it easier
+; to repeat tests across multiple entity types.
+files[] = tests/PanelsEntityViewWebTestCase.test
+files[] = tests/PanelsNodeViewWebTestCase.test
+files[] = tests/PanelsTermViewWebTestCase.test
+files[] = tests/PanelsUserViewWebTestCase.test
+
+; Information added by Drupal.org packaging script on 2016-10-16
+version = "7.x-3.8"
core = "7.x"
project = "panels"
-datestamp = "1326917446"
+datestamp = "1476582295"
diff --git a/sites/all/modules/contrib/panels/panels/panels.install b/sites/all/modules/contrib/panels/panels/panels.install
old mode 100755
new mode 100644
index 6e83d442..11cf7a47
--- a/sites/all/modules/contrib/panels/panels/panels.install
+++ b/sites/all/modules/contrib/panels/panels/panels.install
@@ -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,114 @@ 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_9();
+}
+
+function panels_schema_9() {
+ $schema = panels_schema_8();
+ $schema['panels_allowed_types'] = array(
+ 'fields' => array(
+ 'module' => array(
+ 'description' => 'The name of the module requiring allowed type settings.',
+ 'type' => 'varchar',
+ 'length' => 255,
+ 'not null' => TRUE,
+ 'default' => '',
+ ),
+ 'type' => array(
+ 'description' => 'Ctools content type to allow.',
+ 'type' => 'varchar',
+ 'length' => 255,
+ 'not null' => TRUE,
+ 'default' => '',
+ ),
+ 'allowed' => array(
+ 'description' => 'A boolean for if the type is allowed or not.',
+ 'type' => 'int',
+ 'size' => 'tiny',
+ 'default' => 1,
+ ),
+ ),
+ 'indexes' => array(
+ 'type_idx' => array('type'),
+ ),
+ );
+
+ return $schema;
+ }
+
+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 +465,227 @@ 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();
+ }
+ }
+}
+
+/**
+ * Add a custom table for allowed types.
+ */
+function panels_update_7307() {
+ $schema = panels_schema_9();
+
+ $table_name = 'panels_allowed_types';
+ if (!db_table_exists($table_name)) {
+ db_create_table($table_name, $schema[$table_name]);
+ }
+
+ // Read existing allowed settings and store them in a new table.
+ $variables = db_select('variable', 'v')
+ ->fields('v', array('name'))
+ ->condition('name', '%' . db_like('_allowed_types'), 'LIKE')
+ ->execute()
+ ->fetchCol();
+ foreach ($variables as $name) {
+ $module = str_replace('_allowed_types', '', $name);
+ $variable = variable_get($name);
+ foreach ($variable as $type => $allowed) {
+ $allowed = empty($allowed) ? 0 : 1;
+ db_merge('panels_allowed_types')
+ ->key(array('module' => $module, 'type' => $type))
+ ->fields(array(
+ 'module' => $module,
+ 'type' => $type,
+ 'allowed' => $allowed,
+ ))
+ ->execute();
+ }
+ variable_del($name);
+ }
+}
+
+/**
+ * Rename style permissions.
+ */
+function panels_update_7308() {
+ $permissions = array(
+ 'administer panels display styles',
+ 'administer panels pane styles',
+ 'administer panels region styles',
+ );
+ foreach (array_keys(user_roles(TRUE, 'administer panels styles')) as $rid) {
+ user_role_grant_permissions($rid, $permissions);
+ }
+}
diff --git a/sites/all/modules/contrib/panels/panels/panels.module b/sites/all/modules/contrib/panels/panels/panels.module
old mode 100755
new mode 100644
index ad0cb700..fc25c09b
--- a/sites/all/modules/contrib/panels/panels/panels.module
+++ b/sites/all/modules/contrib/panels/panels/panels.module
@@ -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.9');
+
+/**
+ * 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.8');
+
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.
@@ -37,13 +52,13 @@ function panels_theme() {
$theme = array();
$theme['panels_layout_link'] = array(
- 'variables' => array('title' => NULL, 'id' => NULL, 'image' => NULL, 'link' => NULL),
+ 'variables' => array('title' => NULL, 'id' => NULL, 'image' => NULL, 'link' => NULL, 'class' => NULL),
);
$theme['panels_layout_icon'] = array(
'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',
);
@@ -76,6 +91,20 @@ function panels_theme() {
'template' => 'panels-dashboard-block',
);
+ $theme['panels_add_content_modal'] = array(
+ 'variables' => array('renderer' => NULL, 'categories' => array(), 'region' => NULL, 'category' => NULL, 'column_count' => 2),
+ 'path' => drupal_get_path('module', 'panels') . '/templates',
+ 'file' => '../includes/add-content.inc',
+ 'template' => 'panels-add-content-modal',
+ );
+
+ $theme['panels_add_content_link'] = array(
+ 'variables' => array('renderer' => NULL, 'region' => NULL, 'content_type' => NULL),
+ 'path' => drupal_get_path('module', 'panels') . '/templates',
+ 'file' => '../includes/add-content.inc',
+ 'template' => 'panels-add-content-link',
+ );
+
// We don't need layout and style themes in maintenance mode.
// Disabling this: See http://drupal.org/node/979912 for information.
// if (defined('MAINTENANCE_MODE')) {
@@ -150,7 +179,8 @@ function panels_menu() {
$items['panels/ajax'] = array(
'access arguments' => array('access content'),
'page callback' => 'panels_ajax_router',
- 'theme callback' => 'panels_ajax_theme_callback',
+ 'theme callback' => 'ajax_base_page_theme',
+ 'delivery callback' => 'ajax_deliver',
'type' => MENU_CALLBACK,
);
@@ -243,7 +273,6 @@ function panels_init() {
}
ctools_add_css('panels', 'panels');
- ctools_add_js('panels', 'panels');
}
/**
@@ -255,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 Panels Dashboard.', array('@url' => url('admin/structure/panels'))),
),
'view pane admin links' => array( // @todo
'title' => t("View administrative links on Panel panes"),
@@ -269,6 +298,15 @@ function panels_permission() {
'title' => t("Use the Panels In-Place Editor"),
'description' => t("Allows a user to utilize Panels' In-Place Editor."),
),
+ 'change layouts in place editing' => array(
+ '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(""),
@@ -279,8 +317,20 @@ function panels_permission() {
),
'administer panels styles' => array(
'title' => t("Administer Panels styles"),
+ 'description' => t("DEPRECATED: Modules using this permission should use specific style permissions. See Issue #2329419 for more info."),
+ ),
+ 'administer panels display styles' => array(
+ 'title' => t("Administer Panels display styles"),
+ 'description' => t("Allows a user to administer the styles of Panel displays."),
+ ),
+ 'administer panels pane styles' => array(
+ 'title' => t("Administer Panels pane styles"),
'description' => t("Allows a user to administer the styles of Panel panes."),
),
+ 'administer panels region styles' => array(
+ 'title' => t("Administer Panels region styles"),
+ 'description' => t("Allows a user to administer the styles of Panel regions."),
+ ),
'use panels caching features' => array(
'title' => t("Configure caching settings on Panels"),
'description' => t("Allows a user to configure caching on Panels displays and panes."),
@@ -289,19 +339,21 @@ function panels_permission() {
'title' => t('Use panel locks'),
'description' => t('Allows a user to lock and unlock panes in a panel display.'),
),
+ 'use ipe with page manager' => array(
+ 'title' => t("Use the Panels In-Place Editor with Page Manager"),
+ 'description' => t('Allows users with access to the In-Place editor to administer page manager pages. This permission is only needed for users without "use page manager" access.'),
+ ),
);
}
/**
- * 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
@@ -358,6 +410,7 @@ function panels_ctools_plugin_type() {
'display_renderers' => array(
'classes' => array('renderer'),
),
+ 'panels_storage' => array(),
);
}
@@ -612,7 +665,6 @@ function panels_edit_layout($display, $finish, $destination = NULL, $allowed_lay
/**
* Forms the basis of a panel display
- *
*/
class panels_display {
var $args = array();
@@ -633,8 +685,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;
@@ -648,23 +702,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.
*
@@ -735,6 +776,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);
+ }
}
/**
@@ -763,10 +853,12 @@ function panels_new_pane($type, $subtype, $set_defaults = FALSE) {
$pane->type = $type;
$pane->subtype = $subtype;
if ($set_defaults) {
+ ctools_include('content');
$content_type = ctools_get_content_type($type);
$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;
}
@@ -847,10 +939,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
@@ -860,6 +955,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();
@@ -890,11 +988,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,
@@ -925,6 +1038,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();
}
@@ -958,6 +1073,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();
}
@@ -967,9 +1083,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.
*
@@ -991,10 +1109,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";
@@ -1004,17 +1124,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 = ';
@@ -1050,6 +1175,9 @@ function panels_render_display(&$display, $renderer = NULL) {
if (!empty($display->context)) {
if ($form_context = ctools_context_get_form($display->context)) {
$form_context->form['#theme'] = 'panels_render_display_form';
+ if (empty($form_context->form['#theme_wrappers']) || !in_array('form', $form_context->form['#theme_wrappers'])) {
+ $form_context['#theme_wrappers'][] = 'form';
+ }
$form_context->form['#display'] = &$display;
return $form_context->form;
}
@@ -1066,10 +1194,7 @@ function panels_render_display(&$display, $renderer = NULL) {
* then operate as a theme function of the form.
*/
function theme_panels_render_display_form($vars) {
- // @todo this is probably broken in D7
- $render = $vars['element']['#display']->render();
- $vars['element']['#children'] = $render;
- return theme('form', $vars);
+ return $vars['element']['#display']->render();
}
// @layout
@@ -1108,8 +1233,9 @@ function theme_panels_layout_icon($vars) {
function theme_panels_layout_link($vars) {
$title = $vars['title'];
$image = $vars['image'];
+ $class = $vars['class'];
- $output = '';
+ $output = '';
$output .= $vars['image'];
$output .= '' . $vars['title'] . '';
$output .= '';
@@ -1120,16 +1246,23 @@ function theme_panels_layout_link($vars) {
* Print the layout link. Sends out to a theme function.
* @layout
*/
-function panels_print_layout_link($id, $layout, $link, $options = array()) {
+function panels_print_layout_link($id, $layout, $link, $options = array(), $current_layout = FALSE) {
if (isset($options['query']['q'])) {
unset($options['query']['q']);
}
+ // Setup classes for layout link, including current-layout information
+ $class = array('layout-link');
+ if ($current_layout == $id) {
+ $options['attributes']['class'][] = 'current-layout-link';
+ $class[] = 'current-layout';
+ }
+
ctools_add_css('panels_admin', 'panels');
$file = $layout['path'] . '/' . $layout['icon'];
$image = l(theme('image', array('path' => $file)), $link, array('html' => true) + $options);
$title = l($layout['title'], $link, $options);
- return theme('panels_layout_link', array('title' => $title, 'image' => $image));
+ return theme('panels_layout_link', array('title' => $title, 'image' => $image, 'class' => $class));
}
@@ -1176,7 +1309,7 @@ function template_preprocess_panels_pane(&$vars) {
$vars['classes_array'] = array();
$vars['admin_links'] = '';
- if (user_access('access contextual links')) {
+ if (module_exists('contextual') && user_access('access contextual links')) {
$links = array();
// These are specified by the content.
if (!empty($content->admin_links)) {
@@ -1185,15 +1318,22 @@ function template_preprocess_panels_pane(&$vars) {
// Take any that may have been in the render array we were given and
// move them up so they appear outside the pane properly.
- if (is_array($content->content) && isset($content->content['#contextual_links']) && module_exists('contextual')) {
+ if (is_array($content->content) && isset($content->content['#contextual_links'])) {
$element = array(
'#type' => 'contextual_links',
'#contextual_links' => $content->content['#contextual_links'],
);
unset($content->content['#contextual_links']);
+ // Add content to $element array
+ if (is_array($content->content)) {
+ $element['#element'] = $content->content;
+ }
+
$element = contextual_pre_render_links($element);
- $links += $element['#links'];
+ if(!empty($element['#links'])) {
+ $links += $element['#links'];
+ }
}
if ($links) {
@@ -1243,12 +1383,13 @@ function template_preprocess_panels_pane(&$vars) {
// Add template file suggestion for content type and sub-type.
$vars['theme_hook_suggestions'][] = $base . $delimiter . $content->type;
- $vars['theme_hook_suggestions'][] = $base . $delimiter . $content->type . $delimiter . $content->subtype;
+ $vars['theme_hook_suggestions'][] = $base . $delimiter . strtr(ctools_cleanstring($content->type, array('lower case' => TRUE)), '-', '_') . $delimiter . strtr(ctools_cleanstring($content->subtype, array('lower case' => TRUE)), '-', '_');
$vars['pane_prefix'] = !empty($content->pane_prefix) ? $content->pane_prefix : '';
$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) : '';
@@ -1266,18 +1407,6 @@ function template_preprocess_panels_pane(&$vars) {
}
-/**
- * Menu theme callback.
- *
- * This simply ensures that Panels ajax calls are rendered in the same
- * theme as the original page to prevent .css file confusion.
- */
-function panels_ajax_theme_callback() {
- if (!empty($_POST['ajax_page_state']['theme'])) {
- return $_POST['ajax_page_state']['theme'];
- }
-}
-
/**
* Route Panels' AJAX calls to the correct object.
*
@@ -1299,9 +1428,6 @@ function panels_ajax_router() {
if (count($args) < 3) {
return MENU_NOT_FOUND;
}
- if (!empty($_POST['ajax_page_state']['theme'])) {
- $GLOBALS['custom_theme'] = $_POST['ajax_page_state']['theme'];
- }
ctools_include('display-edit', 'panels');
ctools_include('plugins', 'panels');
@@ -1339,13 +1465,22 @@ 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)) {
- print ajax_render($renderer->commands);
- ajax_footer();
+ return array(
+ '#type' => 'ajax',
+ '#commands' => $renderer->commands,
+ );
+ }
+ else {
+ return $output;
}
- return $output;
}
// --------------------------------------------------------------------------
@@ -1504,7 +1639,7 @@ function panels_edit_cache_break_lock($cache) {
* Get display edit cache on behalf of panel context.
*
* The key is the second half of the key in this form:
- * panel_context:TASK_NAME:HANDLER_NAME;
+ * panel_context:TASK_NAME::HANDLER_NAME::args::url;
*/
function panel_context_panels_cache_get($key) {
ctools_include('common', 'panels');
@@ -1513,7 +1648,7 @@ function panel_context_panels_cache_get($key) {
// this loads the panel context inc even if we don't use the plugin.
$plugin = page_manager_get_task_handler('panel_context');
- list($task_name, $handler_name) = explode(':', $key, 2);
+ list($task_name, $handler_name, $args, $q) = explode('::', $key, 4);
$page = page_manager_get_page_cache($task_name);
if (isset($page->display_cache[$handler_name])) {
return $page->display_cache[$handler_name];
@@ -1527,8 +1662,20 @@ function panel_context_panels_cache_get($key) {
}
$cache = new stdClass();
+ $task = page_manager_get_task($page->task_id);
+ //ctools_context_handler_get_all_contexts($page->task, $page->subtask, $handler);
+ $arguments = array();
+ if ($args) {
+ $arguments = explode('\\', $args);
+ $contexts = ctools_context_handler_get_task_contexts($task, $page->subtask, $arguments);
+ $contexts = ctools_context_handler_get_handler_contexts($contexts, $handler);
+ }
+ else {
+ $contexts = ctools_context_handler_get_all_contexts($page->task, $page->subtask, $handler);
+ }
+
$cache->display = &panels_panel_context_get_display($handler);
- $cache->display->context = ctools_context_handler_get_all_contexts($page->task, $page->subtask, $handler);
+ $cache->display->context = $contexts;
$cache->display->cache_key = 'panel_context:' . $key;
$cache->content_types = panels_common_get_allowed_types('panels_page', $cache->display->context);
$cache->display_title = TRUE;
@@ -1541,7 +1688,7 @@ function panel_context_panels_cache_get($key) {
* Get the Page Manager cache for the panel_context plugin.
*/
function _panel_context_panels_cache_get_page_cache($key, $cache) {
- list($task_name, $handler_name) = explode(':', $key, 2);
+ list($task_name, $handler_name, $args, $q) = explode('::', $key, 4);
$page = page_manager_get_page_cache($task_name);
$page->display_cache[$handler_name] = $cache;
if ($handler_name) {
@@ -1634,6 +1781,32 @@ function panels_page_wizard_panels_cache_set($key, $cache) {
page_manager_set_wizard_cache($wizard_cache);
}
+/**
+ * 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
@@ -1697,6 +1870,105 @@ function panels_print_layout($layout, $content, $meta = 'standard') {
return $renderer->render();
}
+/**
+ * Filter callback for array_filter to remove builders from a list of layouts.
+ */
+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
//
@@ -1709,3 +1981,21 @@ function panels_get_path($file, $base_path = FALSE, $module = 'panels') {
$output = $base_path ? base_path() : '';
return $output . drupal_get_path('module', $module) . '/' . $file;
}
+
+/**
+ * Remove default sidebar related body classes and provide own css classes
+ */
+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 = 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]);
+ }
+ }
+ }
+ if (!empty($panel_body_css['body_classes_to_add'])) {
+ $vars['classes_array'][] = check_plain($panel_body_css['body_classes_to_add']);
+ }
+}
diff --git a/sites/all/modules/contrib/panels/panels/panels_ipe/css/panels_ipe-rtl.css b/sites/all/modules/contrib/panels/panels/panels_ipe/css/panels_ipe-rtl.css
new file mode 100644
index 00000000..abfc50e1
--- /dev/null
+++ b/sites/all/modules/contrib/panels/panels/panels_ipe/css/panels_ipe-rtl.css
@@ -0,0 +1,67 @@
+
+div.panels-ipe-handlebar-wrapper ul {
+ float: right;
+ text-align: left;
+}
+
+div.panels-ipe-handlebar-wrapper li {
+ margin: 0 0 0 .5em;
+ float: right;
+}
+
+div.panels-ipe-draghandle span.panels-ipe-draghandle-icon {
+ float: left;
+}
+
+div.panels-ipe-placeholder {
+ text-align: right;
+}
+
+div.panels-ipe-newblock {
+ left: 30px;
+ right: auto;
+}
+
+div.panels-ipe-handlebar-wrapper li a span,
+div.panels-ipe-newblock a span {
+ text-align: right;
+}
+
+div.panels-ipe-newblock a.style {
+ margin-left: .5em;
+ margin-right: auto;
+}
+
+.panels-ipe-editing .panels-ipe-region {
+ float: right;
+}
+
+/** ============================================================================
+ * Controller form markup
+ */
+
+.ipe-throbber {
+ right: 49%;
+ right: auto;
+}
+
+div.panels-ipe-control .form-submit {
+ padding: 0 34px 2px 0.8em;
+}
+
+#panels-ipe-save,
+#panels-ipe-cancel {
+ background-position: 86% 0;
+}
+
+div.panels-ipe-pseudobutton-container a.panels-ipe-startedit {
+ padding-right: 34px;
+ padding-left: 10px;
+ background-position: 93% 9px;
+}
+
+div.panels-ipe-pseudobutton-container a.panels-ipe-change-layout {
+ padding-right: 34px;
+ padding-left: 10px;
+ background-position: 93% 9px;
+}
diff --git a/sites/all/modules/contrib/panels/panels/panels_ipe/css/panels_ipe.css b/sites/all/modules/contrib/panels/panels/panels_ipe/css/panels_ipe.css
old mode 100755
new mode 100644
index e5d4e833..e7896e26
--- a/sites/all/modules/contrib/panels/panels/panels_ipe/css/panels_ipe.css
+++ b/sites/all/modules/contrib/panels/panels/panels_ipe/css/panels_ipe.css
@@ -1,19 +1,33 @@
+body.panels-ipe {
+ margin-bottom: 60px !important;
+}
+
+/* Hide the IPE toolbar on print output. */
+@media print {
+ #panels-ipe-control-container {
+ display: none !important;
+ }
+ body.panels-ipe {
+ margin-top: 0 !important;
+ }
+}
+
+/* Hide the control container when the overlay is open. */
+html.overlay-open #panels-ipe-control-container {
+ display: none !important;
+}
+html.overlay-open body.panels-ipe {
+ margin-top: 0 !important;
+}
+
div.panels-ipe-handlebar-wrapper {
- border-bottom: #898AAB solid 2px;
+ border-bottom: 1px solid #CCC;
}
.panels-ipe-editing div.panels-ipe-portlet-wrapper {
margin-top: 1em;
- border: #898AAB solid 2px;
- -moz-border-radius-bottomleft:8px;
- -moz-border-radius-bottomright:8px;
- -moz-border-radius-topleft:2px;
- -moz-border-radius-topright:2px;
-
- -webkit-border-radius-bottomleft:8px;
- -webkit-border-radius-bottomright:8px;
- -webkit-border-radius-topleft:2px;
- -webkit-border-radius-topright:2px;
+ border: 1px solid #CCC;
+ width: 100%;
}
/* Hide empty panes when not editing them. */
@@ -25,9 +39,12 @@ div.panels-ipe-handlebar-wrapper {
display: block;
}
-
.panels-ipe-editing div.panels-ipe-portlet-wrapper:hover {
- border: #FF000A solid 2px;
+ border: 1px dashed #CCC;
+}
+
+.panels-ipe-editing .panels-ipe-sort-container {
+ min-height: 40px;
}
.panels-ipe-editing .panels-ipe-sort-container .ui-sortable-helper {
@@ -39,10 +56,13 @@ div.panels-ipe-handlebar-wrapper {
}
.panels-ipe-editing .panels-ipe-sort-container .ui-sortable-placeholder {
+ border: 2px dashed #999;
+ background-color: #FFFF99;
+ margin: 1em 0;
-moz-border-radius: 0;
- -webkit-border-radius: 0;
- border: 1px dotted red;
- background-color: white;
+ -khtml-border-radius: 0;
+ -webkit-border-radius: 0;
+ border-radius: 0;
}
div.panels-ipe-handlebar-wrapper ul {
@@ -53,42 +73,57 @@ div.panels-ipe-handlebar-wrapper ul {
}
div.panels-ipe-handlebar-wrapper li {
- background: none repeat scroll 0 0 transparent;
- list-style: none outside none;
- margin: 0;
+ background: none;
+ list-style-type: none;
+ list-style-image: none;
+ margin: 0 .5em 0 0;
padding: 0;
float: left;
- font: 12px/170% Verdana,sans-serif !important;
-}
-
-div.panels-ipe-handlebar-wrapper li {
- border-top: 1px solid #CCC;
- border-right: 1px solid #CCC;
-}
-
-div.panels-ipe-handlebar-wrapper li.first {
- border-left: 1px solid #CCC;
-}
-
-div.panels-ipe-draghandle {
- background: #898AAB url(../images/dragger.png) top right no-repeat;
- cursor: move;
- height: 24px;
}
+div.panels-ipe-draghandle,
div.panels-ipe-nodraghandle {
- background: #898AAB;
- height: 24px;
+ background: #E9E9E9;
+ background-image: linear-gradient(bottom, #D5D5D5 0%, #FCFCFC 100%);
+ background-image: -o-linear-gradient(bottom, #D5D5D5 0%, #FCFCFC 100%);
+ background-image: -moz-linear-gradient(bottom, #D5D5D5 0%, #FCFCFC 100%);
+ background-image: -webkit-linear-gradient(bottom, #D5D5D5 0%, #FCFCFC 100%);
+ background-image: -ms-linear-gradient(bottom, #D5D5D5 0%, #FCFCFC 100%);
+ background-image: -webkit-gradient(
+ linear,
+ left bottom,
+ left top,
+ color-stop(0, #D5D5D5),
+ color-stop(1, #FCFCFC)
+ );
+
+ padding: 8px 7px;
+}
+
+div.panels-ipe-draghandle span.panels-ipe-draghandle-icon {
+ display: block;
+ float: right;
+ cursor: move;
+ width: 34px;
+ height: 34px;
+ padding: 0 !important; /* override button defaults */
+}
+
+span.panels-ipe-draghandle-icon-inner {
+ display: block;
+ width: 34px;
+ height: 34px;
+ background: url(../images/icon-draggable.png) no-repeat 3px 3px;
}
div.panels-ipe-placeholder {
- border: 1px solid black;
+ border: 2px dashed #999;
padding: .5em;
+ position: relative;
margin-top: .5em;
- background-color: #f6f6f6;
- color: black;
- background-color: white;
- font: 12px/170% Verdana,sans-serif !important;
+ background-color: #ECFAFF;
+ color: #999;
+ font: 15px/1.3em "Open Sans", "Lucida Grande", Tahoma, Verdana, sans-serif;
text-transform: none;
letter-spacing: 0;
text-align: left;
@@ -96,7 +131,10 @@ div.panels-ipe-placeholder {
}
div.panels-ipe-placeholder h3 {
- font-weight: bold;
+ font-weight: normal;
+ font-size: 15px;
+ width: 75px; /* In order to prevent the region title from running into the button, set a width. Initital width only--this will be changed by jQuery */
+ margin: 1.154em 0;
}
/* Hide editor-state-on elements initially */
@@ -105,7 +143,7 @@ div.panels-ipe-placeholder h3 {
}
.panels-ipe-editing .panels-ipe-on {
- display: block;
+ display: block;
}
/* Show editor-state-off elements initially */
@@ -113,27 +151,139 @@ div.panels-ipe-placeholder h3 {
display: block;
}
-div.panels-ipe-handlebar-wrapper li a,
-div.panels-ipe-dragtitle span,
-div.panels-ipe-newblock a {
- background-color: #f6f6f6;
- color: blue;
- display: block;
- padding: 0.1em 0.5em;
- font: 12px/170% Verdana,sans-serif !important;
- text-transform: none;
- letter-spacing: 0;
+div.panels-ipe-newblock {
+ -webkit-box-shadow: 0px 0 5px 5px #ECFAFF;
+ -moz-box-shadow: 0px 0 5px 5px #ECFAFF;
+ box-shadow: 0px 0 5px 5px #ECFAFF;
+ position: absolute;
+ right: 10px;
+ top: 50%;
+ margin-top: -18px; /* some initial guesses to help center the add button
+ panels_ipe.js will evaluate the width and get this pixel-perfect */
+ margin-left: -30px;
+ z-index: 99;
}
-div.panels-ipe-newblock a {
- display: inline;
- border: 1px solid #CCC;
- color: blue;
+div.panels-ipe-newblock li {
+ padding: 0;
+}
+
+div.panels-ipe-handlebar-wrapper li a,
+div.panels-ipe-dragtitle span,
+div.panels-ipe-newblock a,
+span.panels-ipe-draghandle-icon {
+ display: inline-block;
+ border: 1px solid #ccc;
+ padding: 0 8px 1px;
+ font: bold 12px/32px 'Open Sans', 'Lucida Sans', 'Lucida Grande', verdana sans-serif;
+ text-decoration: none;
+ height: 33px;
+ color: #666;
+ cursor: pointer;
+ outline: none;
+ -moz-border-radius: 3px;
+ -khtml-border-radius: 3px;
+ -webkit-border-radius: 3px;
+ border-radius: 3px;
+
+ background: #FAFAFA;
+ background-image: linear-gradient(bottom, #E9EAEC 0%, #FAFAFA 100%);
+ background-image: -o-linear-gradient(bottom, #E9EAEC 0%, #FAFAFA 100%);
+ background-image: -moz-linear-gradient(bottom, #E9EAEC 0%, #FAFAFA 100%);
+ background-image: -webkit-linear-gradient(bottom, #E9EAEC 0%, #FAFAFA 100%);
+ background-image: -ms-linear-gradient(bottom, #E9EAEC 0%, #FAFAFA 100%);
+ background-image: -webkit-gradient(
+ linear,
+ left bottom,
+ left top,
+ color-stop(0, #E9EAEC),
+ color-stop(1, #FAFAFA)
+ );
+
+ -webkit-box-shadow: 0px 3px 3px 0px #d2d2d2;
+ -moz-box-shadow: 0px 3px 3px 0px #d2d2d2;
+ box-shadow: 0px 3px 3px 0px #d2d2d2;
+}
+
+div.panels-ipe-handlebar-wrapper li a span,
+div.panels-ipe-newblock a span {
+ display: block;
+ height: 32px;
+ width: 18px;
+ background-position: center center;
+ background-repeat: no-repeat;
+ text-align: left;
+ text-indent: -9999em;
+}
+
+div.panels-ipe-handlebar-wrapper li.edit a span {
+ background-image: url(../images/icon-settings.png);
+}
+
+div.panels-ipe-handlebar-wrapper li.style a span,
+div.panels-ipe-newblock a.style span {
+ background-image: url(../images/icon-style.png);
+}
+
+div.panels-ipe-newblock a.style {
+ margin-right: .5em;
+}
+
+div.panels-ipe-newblock a.add span {
+ background-image: url(../images/icon-add.png);
+}
+
+div.panels-ipe-handlebar-wrapper li.delete a span {
+ background-image: url(../images/icon-delete.png);
+}
+
+
+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,
+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%);
+ background-image: -moz-linear-gradient(bottom, #C5C5C5 0%, #FAFAFA 100%);
+ background-image: -webkit-linear-gradient(bottom, #C5C5C5 0%, #FAFAFA 100%);
+ background-image: -ms-linear-gradient(bottom, #C5C5C5 0%, #FAFAFA 100%);
+ background-image: -webkit-gradient(
+ linear,
+ left bottom,
+ left top,
+ color-stop(0, #C5C5C5),
+ color-stop(1, #FAFAFA)
+ );
+}
+
+div.panels-ipe-handlebar-wrapper li a:active,
+div.panels-ipe-dragtitle span:active,
+div.panels-ipe-newblock a:active,
+span.panels-ipe-draghandle-icon:active {
+ outline: none;
+ background-image: linear-gradient(bottom, #FFFFFF 0%, #E9EAEC 100%);
+ background-image: -o-linear-gradient(bottom, #FFFFFF 0%, #E9EAEC 100%);
+ background-image: -moz-linear-gradient(bottom, #FFFFFF 0%, #E9EAEC 100%);
+ background-image: -webkit-linear-gradient(bottom, #FFFFFF 0%, #E9EAEC 100%);
+ background-image: -ms-linear-gradient(bottom, #FFFFFF 0%, #E9EAEC 100%);
+ background-image: -webkit-gradient(
+ linear,
+ left bottom,
+ left top,
+ color-stop(0, #FFFFFF),
+ color-stop(1, #E9EAEC)
+ );
+
+ -webkit-box-shadow: 0px 0px 0px 0px #fff;
+ -moz-box-shadow: 0px 0px 0px 0px #fff;
+ box-shadow: 0px 0px 0px 0px #fff;
}
.panels-ipe-editing .panels-ipe-portlet-content {
- margin-bottom: 10px;
- border: transparent dotted 1px;
+ margin: 10px 3px;
overflow: hidden;
}
@@ -158,63 +308,270 @@ div.panels-ipe-draghandle {
visibility: hidden;
}
-/* counteract panels_dnd.css - temporary */
-div.panels-ipe-display-container .panel-pane .pane-title {
- padding: 0;
-}
-
/** ============================================================================
* Controller form markup
*/
div#panels-ipe-control-container {
- z-index: 100;
+ z-index: 99999;
position: fixed;
- margin-left: auto;
- margin-right: auto;
bottom: 0;
- left: 50%;
display: none;
background-color: #000;
- padding: 0.5em 1em;
-/*
- min-width: 9.5em;
- max-width: 14.5em;
- min-height: 2em;
- max-height: 2.5em;
-*/
+ padding: 0.5em 0;
+ width: 100%;
overflow: hidden;
- -moz-border-radius-topleft:5px;
- -moz-border-radius-topright:5px;
- -moz-box-shadow: #333 0px 1px 0px;
- -webkit-border-top-left-radius:5px;
- -webkit-border-top-right-radius:5px;
- -webkit-box-shadow: #333 0px 1px 0px;
+ -moz-box-shadow: 0 3px 20px #000;
+ -webkit-box-shadow: 0 3px 20px #000;
+ box-shadow: 0 3px 20px #000;
}
-div#panels-ipe-control-container .ajax-progress-throbber {
+.ipe-throbber {
+ background-color: #232323;
+ background-image: url("../images/loading-small.gif");
+ background-position: center center;
+ background-repeat: no-repeat;
+ -moz-border-radius: 7px;
+ -webkit-border-radius: 7px;
+ border-radius: 7px;
+ height: 24px;
+ opacity: .9;
+ padding: 4px;
+ width: 24px;
+ /* Can't do center:50% middle: 50%, so approximate it for a typical window size. */
+ left: 49%;
+ position: fixed;
+ top: 48.5%;
+ z-index: 1001;
+}
+
+/* Hide the drupal system throbber image */
+.ipe-throbber .throbber {
display: none;
}
-div.panels-ipe-pseudobutton {
+div.panels-ipe-pseudobutton-container,
+div.panels-ipe-control .form-submit {
cursor: pointer;
- background-color: #333;
- font:normal 11px/15px "Lucida Grande",Tahoma,Verdana,sans-serif;
- color: #FFF;
- -moz-border-radius:5px;
- -moz-box-shadow: #333 0px 1px 0px;
- -webkit-border-radius:5px;
- -webkit-box-shadow: #333 0px 1px 0px;
- padding: 0.3em 0.8em;
- float: left;
+ background: #666666;
+ background-image: linear-gradient(bottom, #383838 0%, #666666 100%);
+ background-image: -o-linear-gradient(bottom, #383838 0%, #666666 100%);
+ background-image: -moz-linear-gradient(bottom, #383838 0%, #666666 100%);
+ background-image: -webkit-linear-gradient(bottom, #383838 0%, #666666 100%);
+ background-image: -ms-linear-gradient(bottom, #383838 0%, #666666 100%);
+
+ background-image: -webkit-gradient(
+ linear,
+ left bottom,
+ left top,
+ color-stop(0, #383838),
+ color-stop(1, #666666)
+ );
+ border: 0;
+ -moz-border-radius: 3px;
+ -webkit-border-radius: 3px;
+ border-radius: 3px;
+ color: #CCC;
+ display: inline-block;
+ font: bold 12px/33px "Open Sans", "Lucida Grande", Tahoma, Verdana, sans-serif;
+ height: 33px;
+ margin: 0 10px;
}
div.panels-ipe-control .form-submit {
- float: left;
- margin: 0.3em 0.5em;
+ padding: 0 0.8em 2px 34px;
+}
+
+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;
+}
+
+div.panels-ipe-pseudobutton-container a {
+ height: 33px;
+ padding: 0 0.8em;
+ display: inline-block;
+ color: #CCC;
+ text-decoration: none;
+}
+
+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%);
+ background-image: url(../images/icon-save.png), -moz-linear-gradient(bottom, #383838 0%, #666666 100%);
+ background-image: url(../images/icon-save.png), -webkit-linear-gradient(bottom, #383838 0%, #666666 100%);
+ background-image: url(../images/icon-save.png), -ms-linear-gradient(bottom, #383838 0%, #666666 100%);
+
+ background-image: url(../images/icon-save.png), -webkit-gradient(
+ linear,
+ left bottom,
+ left top,
+ color-stop(0, #383838),
+ color-stop(1, #666666)
+ );
+}
+
+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%);
+ background-image: url(../images/icon-close.png), -moz-linear-gradient(bottom, #383838 0%, #666666 100%);
+ background-image: url(../images/icon-close.png), -webkit-linear-gradient(bottom, #383838 0%, #666666 100%);
+ background-image: url(../images/icon-close.png), -ms-linear-gradient(bottom, #383838 0%, #666666 100%);
+
+ background-image: url(../images/icon-close.png), -webkit-gradient(
+ linear,
+ left bottom,
+ left top,
+ color-stop(0, #383838),
+ color-stop(1, #666666)
+ );
+}
+
+div.panels-ipe-pseudobutton-container: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%);
+ background-image: -moz-linear-gradient(bottom, #3D3D3D 0%, #999999 100%);
+ background-image: -webkit-linear-gradient(bottom, #3D3D3D 0%, #999999 100%);
+ background-image: -ms-linear-gradient(bottom, #3D3D3D 0%, #999999 100%);
+ background-image: -webkit-gradient(
+ linear,
+ left bottom,
+ left top,
+ color-stop(0, #3D3D3D),
+ color-stop(1, #999999)
+ );
+
+ color: #FFF;
+}
+
+div.panels-ipe-pseudobutton-container a:hover,
+div.panels-ipe-pseudobutton-container a:focus {
+ color: #FFF;
+}
+
+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%);
+ background-image: url(../images/icon-close.png), -webkit-linear-gradient(bottom, #3D3D3D 0%, #999999 100%);
+ background-image: url(../images/icon-close.png), -ms-linear-gradient(bottom, #3D3D3D 0%, #999999 100%);
+
+ background-image: url(../images/icon-close.png), -webkit-gradient(
+ linear,
+ left bottom,
+ left top,
+ color-stop(0, #3D3D3D),
+ color-stop(1, #999999)
+ );
+}
+
+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%);
+ background-image: url(../images/icon-save.png), -webkit-linear-gradient(bottom, #3D3D3D 0%, #999999 100%);
+ background-image: url(../images/icon-save.png), -ms-linear-gradient(bottom, #3D3D3D 0%, #999999 100%);
+
+ background-image: url(../images/icon-save.png), -webkit-gradient(
+ linear,
+ left bottom,
+ left top,
+ color-stop(0, #3D3D3D),
+ color-stop(1, #999999)
+ );
+}
+
+div.panels-ipe-pseudobutton-container:active,
+div.panels-ipe-control .form-submit:active {
+ background: #333;
+ background-image: linear-gradient(bottom, #616161 0%, #333333 100%);
+ background-image: -o-linear-gradient(bottom, #616161 0%, #333333 100%);
+ background-image: -moz-linear-gradient(bottom, #616161 0%, #333333 100%);
+ background-image: -webkit-linear-gradient(bottom, #616161 0%, #333333 100%);
+ background-image: -ms-linear-gradient(bottom, #616161 0%, #333333 100%);
+
+ background-image: -webkit-gradient(
+ linear,
+ left bottom,
+ left top,
+ color-stop(0, #616161),
+ color-stop(1, #333333)
+ );
+
+ color: #CCC;
+}
+
+div.panels-ipe-pseudobutton-container a:active {
+ color: #CCC;
+}
+
+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%);
+ background-image: url(../images/icon-close.png), -webkit-linear-gradient(bottom, #616161 0%, #333333 100%);
+ background-image: url(../images/icon-close.png), -ms-linear-gradient(bottom, #616161 0%, #333333 100%);
+
+ background-image: url(../images/icon-close.png), -webkit-gradient(
+ linear,
+ left bottom,
+ left top,
+ color-stop(0, #616161),
+ color-stop(1, #333333)
+ );
+}
+
+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%);
+ background-image: url(../images/icon-save.png), -webkit-linear-gradient(bottom, #616161 0%, #333333 100%);
+ background-image: url(../images/icon-save.png), -ms-linear-gradient(bottom, #616161 0%, #333333 100%);
+
+ background-image: url(../images/icon-save.png), -webkit-gradient(
+ linear,
+ left bottom,
+ left top,
+ color-stop(0, #616161),
+ color-stop(1, #333333)
+ );
+}
+
+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;
+}
+
+div.panels-ipe-pseudobutton-container a.panels-ipe-change-layout {
+ padding-left: 34px;
+ background: url(../images/icon-change-layout.png) no-repeat 10px 9px;
}
div.panels-ipe-button-container {
margin: 0.3em 0.5em;
+ text-align: center;
}
+form#panels-ipe-edit-control-form {
+ text-align: center;
+}
+
+.panels-ipe-dragbar-admin-title{
+ font-size: 0.9em;
+}
diff --git a/sites/all/modules/contrib/panels/panels/panels_ipe/images/dragger.png b/sites/all/modules/contrib/panels/panels/panels_ipe/images/dragger.png
old mode 100755
new mode 100644
diff --git a/sites/all/modules/contrib/panels/panels/panels_ipe/images/icon-add.png b/sites/all/modules/contrib/panels/panels/panels_ipe/images/icon-add.png
new file mode 100644
index 0000000000000000000000000000000000000000..521bec0aabb39786772eaffe4618b759c11ee74e
GIT binary patch
literal 1052
zcmaJ=J8aWH7`AAI+A3Wr14XDh+?1hh{0Mnq(@;{|A*teE5=(@saqMejHTD_%O5Bdn
z1&I+TPLseuILZ3&etqBfKmAav+?bp=KS5E{WT_}u
ziKU}&Y$WnL{qdccX{^+74Xxvj;X^8Kp(X?+$Jl^XXjt2K58)C;jl^xej_Yb!G?Bv?
z5rzpJkFY6fX*u)^a}#3Fgd4V-qrV-zrGahb=-X+PQ#}c`?Bb3OYdaO)+}Sh*i(bA4
zmO_yTI1n2kblPqphB>;cE0TNUW@*rc;LRL;l2l#QfP{Pq(hQd{xeO07DTYsRLP}T!
zNsi}OKFM;~1kZ`-tjO`8cW4sLx7Nj~TXN*b`Z{)9Ems%M9{2SY8kWmP@k9
zWP%_P!M2NyFyRKXeFYf?rf+-LMlOgHjV9W{Ihtg8Qi9_RWZj_GCekoAG(47PxTvH)
zP*wjAb({e@z*YDs-+u}R`nCtzDh$w;Z<4{S&qkp|Im!Ya+$qlgKny@72XrjT`wk0YG$%f-Fli&ntXhO67(06)CAC(?UKg
z^|>-Kw;br=KGzy>v)oW_vclzDSeS7cgDs?JG#r7`k
TAK!WKoG4Qzr6RvtY25z}{+dVZ
literal 0
HcmV?d00001
diff --git a/sites/all/modules/contrib/panels/panels/panels_ipe/images/icon-change-layout.png b/sites/all/modules/contrib/panels/panels/panels_ipe/images/icon-change-layout.png
new file mode 100644
index 0000000000000000000000000000000000000000..49fa5f26598cd4aa06ca10aaa283ad6dcf76dc49
GIT binary patch
literal 319
zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`EX7WqAsj$Z!;#Vf4nJ
za0`JjgTe~DWM4f5o%`S
literal 0
HcmV?d00001
diff --git a/sites/all/modules/contrib/panels/panels/panels_ipe/images/icon-close.png b/sites/all/modules/contrib/panels/panels/panels_ipe/images/icon-close.png
new file mode 100644
index 0000000000000000000000000000000000000000..7e3f4812d76d54599f933940929e1eb6bedb05f4
GIT binary patch
literal 285
zcmV+&0pk9NP)WAOl;%5f6aO$PCFh
z`Hq<-wo0TDQhZFN5+B6jPoghLR2GpOGHZ<<%%TDjE_!CGQ6j57GoQFaOEXX*SlxAj
zY|RMP4@s@4ATu=2Q6SkeqRpI9lNx0tPO*30iDXccGV8#4=Gk#g1ljA^r333Sf1SH(
jU|$8l_Y^k6TYv!o?gon=DmvD200000NkvXXu0mjfP;hTI
literal 0
HcmV?d00001
diff --git a/sites/all/modules/contrib/panels/panels/panels_ipe/images/icon-configure.png b/sites/all/modules/contrib/panels/panels/panels_ipe/images/icon-configure.png
new file mode 100644
index 0000000000000000000000000000000000000000..348a8f944bc8d612fa50bfeb5bfde1290530d151
GIT binary patch
literal 546
zcmV+-0^R+IP)
zR5*=|lCh53Kp2ESN9?rc&J9vbMR^Vl4F#b`A~ci{Pmu5imp9-I;+BRa;sL@*G;W+w
zy5b_y(1Em-8?IoT?45k!R$A@O@0tIfSvlZ^wOA}t;G=`@CX>nUI$oo?ESJj=2*=~`
z1As9m_IRPk`3$5LF92ArRtc~MZh$H9-Qio;;Df_e?F7Wb;qcf1kTh~)fUm&Z!vNo$
zsH)vKSCqoEG8&x34vMh0SM!+YJIO}%1
z^DN6^E^l({eY06%0
z_!33Y-5UT&M@c71NZLwjNt!u~r28m}5=m2sPm)}Gy7KjVd0
kgO+8Plx2B#JAH}w2-y0DCEr0vw*UYD07*qoM6N<$g6QG&djJ3c
literal 0
HcmV?d00001
diff --git a/sites/all/modules/contrib/panels/panels/panels_ipe/images/icon-delete.png b/sites/all/modules/contrib/panels/panels/panels_ipe/images/icon-delete.png
new file mode 100644
index 0000000000000000000000000000000000000000..4b3bc18feb8127ef311d4fce2c8a151dc04cf5ea
GIT binary patch
literal 658
zcmV;D0&V??P)dbVG7wVRUJ4ZXi@?ZDjy6FEKPPF*0qC)?EMq0qaRb
zK~y-6-IFm+8$lF?zc)K$b{$)BB-V*i`2aXcLy;4pEi56Qz?a|-NL(fzqCtqtWiEgO
zVvD4)K-hS9c6MJ1SOmlcY4b~?8U1?mY3AvF!ZWFA0(=5K0$aRP3H%0riO8BwQq@tG
zWoK!c>To!GvC=fvEX&SRb@cp>eZ|<$^L)44?V_qQO#^^21`#38^Ic#YxO@Vr>U&@W
z41h0#!Js=F4%yq=yF55J_yKTqbhLkRax(JXcY*J!`VP1OE=5(pW?A;L*Xv=eC5~f^
zF?jFs-UHC-bm(+CG)+TM6oe31E|(l1AAhqz=3v%z+yU`p0-7k
z$>cmu)7z@57>~ynweJf2?+OaK4?9CSrkbW?9;ba!ELWdK2BZ(?O2Mrm?ocW-iQb09-gHF34$HUIzx2uVai
zR7i=nR!wMASrqo<$O)HK$Kj?RG#@7{Or
z_nn`6&$$AhDI_fbHW<@cA;i+>Vtfu+CCTPcD3lC^LP?U%BrE?fGMVJ2SS&W^^?K>`
zdKrtw21#xrDSvG;iR8wM7cXA$dcE}deDwKz^m@I#bm`Isk{d}%UxiH5G(pnS-`{^G
z5D4TO8yo5O`|0=l+1S{~Kp>F6e*O9xk{(^xMLE2Rate|pneN}e?@uHWrxZnz9S#Sa
zPA8mBCmaq36h)B}iNvV~4<7g{Dk@Cn@XA_5vg+8eV~29N+&-Vrr@ngiYV+daq5=R`
zt2Niq(D3x_+qct-qTKE8@4qR8`0GmvWdJr~G#x#9^vC)6c@F?M9F9M3+_=#R;2D4n
zfQ%4A`!~D~PM4->LXspIE8*4*fE0if$qlkB>vp?+WwR{n0H%ZxzZV%O8Mw>3u4}R^
zvlxF(4oOx>lH?v89SwGOceeqsmW#kTV(sqkZW|pP4N8*aCb@=Vbz+209T*rm(9_d%
zYhq&JFaUcASSFQ9Ev3_Gq|<4nQmG}ZgtA!d6B84MdwP0q4Gat%0HA(wPmKz)DISlX
zudA!etE$RaES4m>hvXJx)RXj*Y#_PA7!Af+eUaXtSS*%QRh4yhb@_Nae%>e!l>i`&
z+SqXNyem`o;EEEZH&R(_PQu)dyDRaL=a
zv3!(JmSq$oCj*$hef#$D)2C1OC6md$X0sVW2w1JwoY`zn=ks|T0OsfCmjKMJ!#C^k
zcz$y@92UcPDVxnY7Z(>5lE`MW*tv7((7AKxdI8Le!l40Bd-dwo<0B&@-6ZAa=H^Fz
zeSK#EOc}r#01E)BQPdBya!2i0DGUJM>+S75`{c=!79oTd4u`)#apJ@e049YHe;4OM
zCRsB)JlxgZ-aZqJM(>cUDaluTQ&ZC$kH^P!#|r$rf2u=-TTJys90<^o6RE2a$#aA@~j{WE|=@4g9i_Ow|n>Q
zUjh6ngjilD6{{9jkhG9=kW@N};Rc>5$tT5Yt(w~yp3-WTs2fZWF%`lR;M+1Yt0lgaE;RaJfb`0?h#rFOgBxvg8b
zKAoDHnzq~RcN2+3+4fYn0Rzw@k;vqRsgjk{bftdbVG7wVRUJ4ZXi@?ZDjy6FEKPPF*0qC)?EMq0gy>V
zK~y-6jgvu6!ax*;zcD1;Rb)9V9Fy*?;R4(M64oS|%mMHOmJ`69NhIL_mJ^5vAkq`4
zn_1%taM9N|LNR^Gq|^V+`}*d+S9LfXXktn!wARLZ|Eaa!h&%+0_kO3Eg1X&q3cLer
zpfB<#a0}ct21!OaFgS9pz4yb$pwVcQOD31V9bkZ$%HL{40Xm&dJ9te61W*9EsteLu
zPXN64^H8_e)?KXt`WH2jJ}?7jvPWy3YOULpS1V)zOeu?PS^!CsWWYq$KH#>KB)JEk
zB{&uT1TfCI49EZ!K(E)^3Hd)Ow%cubt~o7$IF9du4P{5_?2F&osWmki3=CxlUPb$s
z)B)xJd@9d8&-2|$MsXZ}9BIqdYPAFykH-dh68$MSa|(*0=vXt=CW;~x=mlk=Papuw
zT5BYD30wz3@V5b1&bj@$Vk-b^ZJV;#|8=ea`isS4U+1g_G7BI@;Qylh+pFx%xvx~9
zr2rnBb1Cpv>CU+!WycP)dbVG7wVRUJ4ZXi@?ZDjy6FEKPPF*0qC)?EMq0YOPb
zK~y-6ozuTm)%u14pnN=j+
zO-P!i#|R0@%FJ9*6#MvEU_PIp03=;e6ng;Ib>f`MS{+o98UO$;PLihS9m$;JgPGwN
zVY}V#+xt2@naySy$#*kD0AObKo6Y6~sO$PX&Uie|oO3%#hkn2RCJEtr{t5gVXF8oe
zl6(z+c4p?ndq(o5Yw8n3Qr;RpAz21&?Y;l(LYht%i$&8xKtK|49DjK4vo4^n>+eY<
zW$lm63{eyTK-mSH#gUY?fv_q7>#LCEa+!y_fH-d43c%B)E*fODTCIFPSxL!-G(ZEN0l@R;&!0VeHaj~zGc$Ad?%k=Wsfme+k&%(}=g*%$eY&@|
zx2LD4y}iA;x!Ldcd%a$d$5U2T=61V_i;MH~^YilZa&mIg)6;D>o5f-=8jVp=Q5uZ~
z!!Z72005$%Bg->au2`Iwn`xaFF9cs~eJ2u20Tzhk*Zd`D01*H8UQFYI`ODUyXk3ED
zxvyN++QFpM(*8|9Q7p5Egbv#wpF!Ux5mbup#Y36|oiD>$7)tUFrKS#Tvj!a-b{=%Z
z8772J&V66bNmu_e`wf){qRI^#lGs)nsiW6e7{)}AjSKZOtyhRdNHEM07)EI+NGui+
zUb9-!rKEp-T=+q_ufOfkdxsZxcJ**g2g2EH`k!tb*&XcV7zK=|u5mObCoU|)p$MpB
z$0UZz(BUx!B#D6C3`MPBBu$R5agCnmrcH5o&i(HLQaHl}knE%xex4MY>rlFzvPfK(S
z@GGvUvjuF%+)B&HZgm=nIoN;2re=#DX=V|
zZP6;q8ttuRv51J=088P7M3Vgqy=L1@}L!tBxRo?z2~Kr8Oye8=_lexufMj=f+|
zqH^_+0aqR|5HKQ@>xZn<6n@vq@f+=+DlZ_OI7&d1^8+g55BK3#T~aQ!-*Xm&tdJie%4_B
zXF=}#6E(=pS`3vWS@k&g+La39Wi(|%p&%S8d`x3f6Unp!o24DQ|7t0x
zXP=xjP_rH1b7$Z7z7%x&1?a}LJSbM3>K+VE70%g|lCLzZg1o)MPcsMYVbF*3>>WF_Eg)56Gk0FXPQVQ?ma__1u$b&@uA`)
z21W!-$_Mr2C>GGtv{pxhlYsOlM~^9rDICw%!S{$iKOkeZ8k`_5WXh2zX3xK$e1~7^
zEa*kPop*~1-e2v1sn~ybfxY839{a|Co-_Ev+B@0;!!>KYsrg_@o34U`
zKtY~SHB2nkX_T0T6A6SYYSdiDGZ@|*XzRt_4c=8HN8%43;*oji;{`hMDL{^%(IW!U
zxBuEVapFflgM6{6`D*(U&l~+Pi9G({q2JHn)^+A&oikiMa@DXr_@z|%Zc1KU)8VXzT^_4ucOtb;jpNj>
z-j+o~U=>6Vr>i*<3P@C%AklPyZD~v1v$r7;4eaBpSltoMYtrdxrf+xE*=Pm^MdYU@
z7_$CG4vdMIL|7yimgsfTF#v4lN;Hso^0zmMDY#FMfHS)(j>y@NS?0*oMOveo
zqU|h+GrAi6B0a(f;t43E(h33$0a&$_k|Nz|vORRT=4dzK;OncVrA=S&3vm1NRi8xH
zafk?tH>nUC86*uRsr2GX-VWEDdOh?
z>Bkkz8Q18?eXV`UC!>)|otN(Yzq8>VO|c(3yJbC(eLG<-KgEh-KEWB^m#31LMp?_9
z@;K7JMX)I*siPqyPw8Y8dqbZ&6F?B%SaXR^R7xJC8B2AqSI6`OOXhsEGClW5stZ?=
zSynpD;x!QqqO;V|G7yxM`B|k*_9n@HX;4{VQK4;e?!CjE{_gj4cx->`!DwGN&TKP#
z>kTppe%GK?%TT3BDHID~vs{Y6Z(bZ1LwfQSiz0}0%s^cg%D5ruFD>v5)dh}{VXTgd
gkVHhdSYkS?`sR^#23&_qB-rHTo?$`S3&$7y4~a^U-v9sr
literal 0
HcmV?d00001
diff --git a/sites/all/modules/contrib/panels/panels/panels_ipe/includes/panels_ipe.pipelines.inc b/sites/all/modules/contrib/panels/panels/panels_ipe/includes/panels_ipe.pipelines.inc
old mode 100755
new mode 100644
diff --git a/sites/all/modules/contrib/panels/panels/panels_ipe/js/panels_ipe.js b/sites/all/modules/contrib/panels/panels/panels_ipe/js/panels_ipe.js
old mode 100755
new mode 100644
index 3f2302fe..f6cae923
--- a/sites/all/modules/contrib/panels/panels/panels_ipe/js/panels_ipe.js
+++ b/sites/all/modules/contrib/panels/panels/panels_ipe/js/panels_ipe.js
@@ -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: {},
@@ -15,9 +10,11 @@ Drupal.PanelsIPE = {
$('a.pane-delete:not(.pane-delete-processed)', context)
.addClass('pane-delete-processed')
.click(function() {
- if (confirm('Remove this pane?')) {
+ if (confirm(Drupal.t('Remove this pane?'))) {
$(this).parents('div.panels-ipe-portlet-wrapper').fadeOut('medium', function() {
+ var $sortable = $(this).closest('.ui-sortable');
$(this).empty().remove();
+ $sortable.trigger('sortremove');
});
$(this).parents('div.panels-ipe-display-container').addClass('changed');
}
@@ -26,16 +23,36 @@ Drupal.PanelsIPE = {
}
}
-// A ready function should be sufficient for this, at least for now
-$(function() {
- $.each(Drupal.settings.PanelsIPECacheKeys, function() {
- Drupal.PanelsIPE.editors[this] = new DrupalPanelsIPE(this, Drupal.settings.PanelsIPESettings[this]);
- Drupal.PanelsIPE.editors[this].showContainer();
- });
-});
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)')
+ .addClass('panels-ipe-processed')
+ .each(function() {
+ // If we're replacing an old IPE, clean it up a little.
+ if (Drupal.PanelsIPE.editors[key]) {
+ Drupal.PanelsIPE.editors[key].editing = false;
+ }
+ Drupal.PanelsIPE.editors[key] = new DrupalPanelsIPE(key);
+ Drupal.PanelsIPE.editors[key].showContainer();
+ });
+ }
+ $('.panels-ipe-hide-bar').once('panels-ipe-hide-bar-processed').click(function() {
+ Drupal.PanelsIPE.editors[key].hideContainer();
+ });
Drupal.PanelsIPE.bindClickDelete(context);
}
};
@@ -51,8 +68,10 @@ Drupal.behaviors.PanelsIPE = {
* discrete IPE elements. This will result in greater IPE flexibility.
*/
function DrupalPanelsIPE(cache_key, cfg) {
+ cfg = cfg || {};
var ipe = this;
this.key = cache_key;
+ this.lockPath = null;
this.state = {};
this.container = $('#panels-ipe-control-container');
this.control = $('div#panels-ipe-control-' + cache_key);
@@ -63,12 +82,75 @@ function DrupalPanelsIPE(cache_key, cfg) {
opacity: 0.75, // opacity of sortable while sorting
items: 'div.panels-ipe-portlet-wrapper',
handle: 'div.panels-ipe-draghandle',
- cancel: '.panels-ipe-nodrag'
+ cancel: '.panels-ipe-nodrag',
+ dropOnEmpty: true
}, cfg.sortableOptions || {});
this.regions = [];
this.sortables = {};
+ $(document).bind('CToolsDetachBehaviors', function() {
+ // If the IPE is off and the container is not visible, then we need
+ // to reshow the container on modal close.
+ if (!$('.panels-ipe-form-container', ipe.control).html() && !ipe.container.is(':visible')) {
+ ipe.showContainer();
+ ipe.cancelLock();
+ }
+
+ // If the IPE is on and we've hidden the bar for a modal, we need to
+ // re-display it.
+ if (ipe.topParent && ipe.topParent.hasClass('panels-ipe-editing') && ipe.container.is(':not(visible)')) {
+ ipe.showContainer();
+ }
+ });
+
+
+ // If a user navigates away from a locked IPE, cancel the lock in the background.
+ $(window).bind('beforeunload', function() {
+ if (!ipe.editing) {
+ return;
+ }
+
+ if (ipe.topParent && ipe.topParent.hasClass('changed')) {
+ ipe.changed = true;
+ }
+
+ if (ipe.changed) {
+ return Drupal.t('This will discard all unsaved changes. Are you sure?');
+ }
+ });
+
+ // If a user navigates away from a locked IPE, cancel the lock in the background.
+ $(window).bind('unload', function() {
+ ipe.cancelLock(true);
+ });
+
+ /**
+ * If something caused us to abort what we were doing, send a background
+ * cancel lock request to the server so that we do not leave stale locks
+ * hanging around.
+ */
+ this.cancelLock = function(sync) {
+ // If there's a lockpath and an ajax available, inform server to clear lock.
+ // We borrow the ajax options from the customize this page link.
+ if (ipe.lockPath && Drupal.ajax['panels-ipe-customize-page']) {
+ var ajaxOptions = {
+ type: 'POST',
+ url: ipe.lockPath
+ }
+
+ if (sync) {
+ ajaxOptions.async = false;
+ }
+
+ // Make sure we don't somehow get another one:
+ ipe.lockPath = null;
+
+ // Send the request. This is synchronous to prevent being cancelled.
+ $.ajax(ajaxOptions);
+ }
+ }
+
this.activateSortable = function(event, ui) {
if (!Drupal.settings.Panels || !Drupal.settings.Panels.RegionLock) {
// don't bother if there are no region locks in play.
@@ -76,8 +158,7 @@ function DrupalPanelsIPE(cache_key, cfg) {
}
var region = event.data.region;
- var $pane = $(event.srcElement).parents('.panels-ipe-portlet-wrapper');
- var paneId = $pane.attr('id').replace('panels-ipe-paneid-', '');
+ var paneId = ui.item.attr('id').replace('panels-ipe-paneid-', '');
var disabledRegions = false;
@@ -109,7 +190,7 @@ function DrupalPanelsIPE(cache_key, cfg) {
}
this.initSorting = function() {
- var $region = $(this).parent('.panels-ipe-region');
+ var $region = $(this).parents('.panels-ipe-region');
var region = $region.attr('id').replace('panels-ipe-regionid-', '');
ipe.sortables[region] = $(this).sortable(ipe.sortableOptions);
ipe.regions.push(region);
@@ -117,6 +198,7 @@ function DrupalPanelsIPE(cache_key, cfg) {
};
this.initEditing = function(formdata) {
+ ipe.editing = true;
ipe.topParent = $('div#panels-ipe-display-' + cache_key);
ipe.backup = this.topParent.clone();
@@ -137,44 +219,30 @@ 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');
element_settings.setClick = true;
element_settings.event = 'click';
element_settings.progress = { 'type': 'throbber' };
+ element_settings.ipe_cache_key = cache_key;
var base = $(this).attr('id');
- Drupal.ajax[base] = new Drupal.ajax(base, this, element_settings);
- if ($(this).attr('id') == 'panels-ipe-save') {
- Drupal.ajax[base].options.beforeSerialize = function (element_settings, options) {
- ipe.saveEditing();
- return Drupal.ajax[base].beforeSerialize(element_settings, options);
- };
- Drupal.ajax[base].oldEventResponse = Drupal.ajax[base].eventResponse;
- Drupal.ajax[base].eventResponse = function (element, event) {
- var val = this.oldEventResponse(element, event);
- if (this.ajaxing) {
- ipe.hideContainer();
- }
- return val;
- };
-
- }
- if ($(this).attr('id') == 'panels-ipe-cancel') {
- Drupal.ajax[base].options.beforeSend = function () {
- return ipe.cancelEditing();
- };
- }
+ Drupal.ajax[ipe.base] = new Drupal.ajax(base, this, element_settings);
});
// Perform visual effects in a particular sequence.
- $('.panels-ipe-on').show('normal');
+ // .show() + .hide() cannot have speeds associated with them, otherwise
+ // 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');
+
};
this.hideContainer = function() {
@@ -183,7 +251,6 @@ function DrupalPanelsIPE(cache_key, cfg) {
this.showContainer = function() {
ipe.container.slideDown('normal');
- ipe.container.css('margin-left', '-' + parseInt(ipe.container.outerWidth() / 2) + 'px');
};
this.showButtons = function() {
@@ -198,16 +265,23 @@ function DrupalPanelsIPE(cache_key, cfg) {
ipe.showContainer();
};
- this.endEditing = function(data) {
- $('.panels-ipe-form-container', ipe.control).empty();
+ this.endEditing = function() {
+ ipe.editing = false;
+ ipe.lockPath = null;
+ $('.panels-ipe-form-container').empty();
// 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('fast');
- ipe.topParent.removeClass('panels-ipe-editing');
- $('div.panels-ipe-sort-container', ipe.topParent).sortable("destroy");
+ $('div.panels-ipe-on').hide();
+
+ $('.panels-ipe-editing').removeClass('panels-ipe-editing');
+ $('div.panels-ipe-sort-container.ui-sortable', ipe.topParent).sortable("destroy");
};
this.saveEditing = function() {
@@ -223,29 +297,34 @@ function DrupalPanelsIPE(cache_key, cfg) {
val += id;
}
});
- $('input[name="panel[pane][' + region + ']"]', ipe.control).val(val);
+ $('[name="panel[pane][' + region + ']"]', ipe.control).val(val);
});
}
+ this.cancelIPE = function() {
+ ipe.hideContainer();
+ ipe.topParent.fadeOut('medium', function() {
+ ipe.topParent.replaceWith(ipe.backup.clone());
+ ipe.topParent = $('div#panels-ipe-display-' + ipe.key);
+
+ // Processing of these things got lost in the cloning, but the classes remained behind.
+ // @todo this isn't ideal but I can't seem to figure out how to keep an unprocessed backup
+ // that will later get processed.
+ $('.ctools-use-modal-processed', ipe.topParent).removeClass('ctools-use-modal-processed');
+ $('.pane-delete-processed', ipe.topParent).removeClass('pane-delete-processed');
+ ipe.topParent.fadeIn('medium');
+ Drupal.attachBehaviors();
+ });
+ };
+
this.cancelEditing = function() {
if (ipe.topParent.hasClass('changed')) {
ipe.changed = true;
}
if (!ipe.changed || confirm(Drupal.t('This will discard all unsaved changes. Are you sure?'))) {
- ipe.hideContainer();
- ipe.topParent.fadeOut('medium', function() {
- ipe.topParent.replaceWith(ipe.backup.clone());
- ipe.topParent = $('div#panels-ipe-display-' + ipe.key);
-
- // Processing of these things got lost in the cloning, but the classes remained behind.
- // @todo this isn't ideal but I can't seem to figure out how to keep an unprocessed backup
- // that will later get processed.
- $('.ctools-use-modal-processed', ipe.topParent).removeClass('ctools-use-modal-processed');
- $('.pane-delete-processed', ipe.topParent).removeClass('pane-delete-processed');
- ipe.topParent.fadeIn('medium');
- Drupal.attachBehaviors();
- });
+ this.cancelIPE();
+ return true;
}
else {
// Cancel the submission.
@@ -255,96 +334,159 @@ 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('');
// Move our gadgets outside of the sort container so that sortables
// cannot be placed after them.
$('div.panels-ipe-portlet-static', this).each(function() {
- $(this).appendTo($(this).parent().parent());
+ $(this).prependTo($(this).parent().parent());
});
-
- // Also remove the last panel separator.
- $('div.panel-separator', this).filter(':last').remove();
-
- // Add a marker so we can drag things to empty containers.
- $('div.panels-ipe-sort-container', this).append(' ');
});
}
this.createSortContainers();
- var element_settings = {
- url: ipe.cfg.formPath,
- event: 'click',
- keypress: false,
- // No throbber at all.
- progress: { 'type': 'none' }
- };
-
- Drupal.ajax['ipe-ajax'] = new Drupal.ajax('ipe-ajax', $('div.panels-ipe-startedit', this.control).get(0), element_settings);
-
- Drupal.ajax['ipe-ajax'].oldEventResponse = Drupal.ajax['ipe-ajax'].eventResponse;
- Drupal.ajax['ipe-ajax'].eventResponse = function (element, event) {
- this.oldEventResponse(element, event);
- if (this.ajaxing) {
- ipe.hideContainer();
- $('div.panels-ipe-off').fadeOut('normal');
- }
- };
-
-/*
- var ajaxOptions = {
- type: "POST",
- url: ,
- data: { 'js': 1 },
- global: true,
- success: Drupal.CTools.AJAX.respond,
- error: function(xhr) {
- Drupal.CTools.AJAX.handleErrors(xhr, ipe.cfg.formPath);
- },
- dataType: 'json'
- };
-
- $('div.panels-ipe-startedit', this.control).click(function() {
- var $this = $(this);
- $.ajax(ajaxOptions);
- });
- */
};
$(function() {
Drupal.ajax.prototype.commands.initIPE = function(ajax, data, status) {
if (Drupal.PanelsIPE.editors[data.key]) {
Drupal.PanelsIPE.editors[data.key].initEditing(data.data);
+ Drupal.PanelsIPE.editors[data.key].lockPath = data.lockPath;
+ }
+ Drupal.attachBehaviors();
+
+ };
+
+ Drupal.ajax.prototype.commands.IPEsetLockState = function(ajax, data, status) {
+ if (Drupal.PanelsIPE.editors[data.key]) {
+ Drupal.PanelsIPE.editors[data.key].lockPath = data.lockPath;
+ }
+ };
+
+ Drupal.ajax.prototype.commands.addNewPane = function(ajax, data, status) {
+ if (Drupal.PanelsIPE.editors[data.key]) {
+ Drupal.PanelsIPE.editors[data.key].changed = true;
+ }
+ };
+
+ Drupal.ajax.prototype.commands.cancelIPE = function(ajax, data, status) {
+ if (Drupal.PanelsIPE.editors[data.key]) {
+ Drupal.PanelsIPE.editors[data.key].cancelIPE();
+ Drupal.PanelsIPE.editors[data.key].endEditing();
}
};
Drupal.ajax.prototype.commands.unlockIPE = function(ajax, data, status) {
if (confirm(data.message)) {
- var ajaxOptions = {
- type: "POST",
- url: data.break_path,
- data: { 'js': 1 },
- global: true,
- success: Drupal.CTools.AJAX.respond,
- error: function(xhr) {
- Drupal.CTools.AJAX.handleErrors(xhr, ipe.cfg.formPath);
- },
- dataType: 'json'
- };
-
+ var ajaxOptions = ajax.options;
+ ajaxOptions.url = data.break_path;
$.ajax(ajaxOptions);
- };
+ }
+ else {
+ Drupal.PanelsIPE.editors[data.key].endEditing();
+ }
};
Drupal.ajax.prototype.commands.endIPE = function(ajax, data, status) {
if (Drupal.PanelsIPE.editors[data.key]) {
- Drupal.PanelsIPE.editors[data.key].endEditing(data);
+ Drupal.PanelsIPE.editors[data.key].endEditing();
}
};
+ 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.
+ */
+ Drupal.ajax.prototype.ipeReplacedEventResponse = Drupal.ajax.prototype.eventResponse;
+ Drupal.ajax.prototype.eventResponse = function (element, event) {
+ if (element.ipeCancelThis) {
+ element.ipeCancelThis = null;
+ return false;
+ }
+
+ if ($(this.element).attr('id') == 'panels-ipe-cancel') {
+ if (!Drupal.PanelsIPE.editors[this.element_settings.ipe_cache_key].cancelEditing()) {
+ return false;
+ }
+ }
+
+ var retval = this.ipeReplacedEventResponse(element, event);
+ if (this.ajaxing && this.element_settings.ipe_cache_key) {
+ // Move the throbber so that it appears outside our container.
+ if (this.progress.element) {
+ $(this.progress.element).addClass('ipe-throbber').appendTo($('body'));
+ }
+ Drupal.PanelsIPE.editors[this.element_settings.ipe_cache_key].hideContainer();
+ }
+ // @TODO $('#panels-ipe-throbber-backdrop').remove();
+ return retval;
+ };
+
+ /**
+ * Override the eventResponse on ajax.js so we can add a little extra
+ * behavior.
+ */
+ Drupal.ajax.prototype.ipeReplacedError = Drupal.ajax.prototype.error;
+ Drupal.ajax.prototype.error = function (response, uri) {
+ var retval = this.ipeReplacedError(response, uri);
+ if (this.element_settings.ipe_cache_key) {
+ Drupal.PanelsIPE.editors[this.element_settings.ipe_cache_key].showContainer();
+ }
+ };
+
+ Drupal.ajax.prototype.ipeReplacedBeforeSerialize = Drupal.ajax.prototype.beforeSerialize;
+ Drupal.ajax.prototype.beforeSerialize = function (element_settings, options) {
+ if ($(this.element).hasClass('panels-ipe-save')) {
+ Drupal.PanelsIPE.editors[this.element_settings.ipe_cache_key].saveEditing();
+ };
+ return this.ipeReplacedBeforeSerialize(element_settings, options);
+ };
});
+/**
+ * Apply margin to bottom of the page.
+ *
+ * Note that directly applying marginBottom does not work in IE. To prevent
+ * flickering/jumping page content with client-side caching, this is a regular
+ * Drupal behavior.
+ *
+ * @see admin_menu.js via https://drupal.org/project/admin_menu
+ */
+Drupal.behaviors.panelsIpeMarginBottom = {
+ attach: function () {
+ $('body:not(.panels-ipe)').addClass('panels-ipe');
+ }
+};
+
})(jQuery);
diff --git a/sites/all/modules/contrib/panels/panels/panels_ipe/panels_ipe.api.php b/sites/all/modules/contrib/panels/panels/panels_ipe/panels_ipe.api.php
new file mode 100644
index 00000000..e026c5be
--- /dev/null
+++ b/sites/all/modules/contrib/panels/panels/panels_ipe/panels_ipe.api.php
@@ -0,0 +1,31 @@
+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;
+}
diff --git a/sites/all/modules/contrib/panels/panels/panels_ipe/panels_ipe.info b/sites/all/modules/contrib/panels/panels/panels_ipe/panels_ipe.info
old mode 100755
new mode 100644
index f1aa9853..299c694a
--- a/sites/all/modules/contrib/panels/panels/panels_ipe/panels_ipe.info
+++ b/sites/all/modules/contrib/panels/panels/panels_ipe/panels_ipe.info
@@ -6,9 +6,9 @@ core = 7.x
configure = admin/structure/panels
files[] = panels_ipe.module
-; Information added by drupal.org packaging script on 2012-01-18
-version = "7.x-3.0"
+; Information added by Drupal.org packaging script on 2016-10-16
+version = "7.x-3.8"
core = "7.x"
project = "panels"
-datestamp = "1326917446"
+datestamp = "1476582295"
diff --git a/sites/all/modules/contrib/panels/panels/panels_ipe/panels_ipe.module b/sites/all/modules/contrib/panels/panels/panels_ipe/panels_ipe.module
old mode 100755
new mode 100644
index c2c6f897..35dfa6f5
--- a/sites/all/modules/contrib/panels/panels/panels_ipe/panels_ipe.module
+++ b/sites/all/modules/contrib/panels/panels/panels_ipe/panels_ipe.module
@@ -39,7 +39,7 @@ function panels_ipe_theme() {
'variables' => array('output' => NULL, 'pane' => NULL, 'display' => NULL, 'renderer' => NULL),
),
'panels_ipe_region_wrapper' => array(
- 'variables' => array('output' => NULL, 'region_id' => NULL, 'display' => NULL, 'renderer' => NULL),
+ 'variables' => array('output' => NULL, 'region_id' => NULL, 'display' => NULL, 'controls' => NULL, 'renderer' => NULL),
),
'panels_ipe_add_pane_button' => array(
'variables' => array('region_id' => NULL, 'display' => NULL, 'renderer' => NULL),
@@ -53,9 +53,6 @@ function panels_ipe_theme() {
'panels_ipe_toolbar' => array(
'variables' => array('buttons' => NULL),
),
- 'panels_ipe_edit_button' => array(
- 'variables' => array('class' => array(), 'text' => NULL),
- ),
);
}
@@ -76,67 +73,140 @@ function theme_panels_ipe_placeholder_pane($vars) {
return $output;
}
-function theme_panels_ipe_pane_wrapper($vars) {
- $output = $vars['output'];
+function template_preprocess_panels_ipe_pane_wrapper(&$vars) {
$pane = $vars['pane'];
$display = $vars['display'];
$renderer = $vars['renderer'];
$content_type = ctools_get_content_type($pane->type);
$subtype = ctools_content_get_subtype($content_type, $pane->subtype);
- $links = array();
+ $vars['links'] = array();
if (ctools_content_editable($content_type, $subtype, $pane->configuration)) {
- $links['edit'] = array(
- 'title' => isset($content_type['edit text']) ? $content_type['edit text'] : t('Settings'),
+ $vars['links']['edit'] = array(
+ 'title' => isset($content_type['edit text']) ? '' . $content_type['edit text'] . '' : '' . t('Settings') . '',
'href' => $renderer->get_url('edit-pane', $pane->pid),
+ 'html' => TRUE,
'attributes' => array(
- 'class' => 'ctools-use-modal',
+ 'class' => array('ctools-use-modal', 'panels-ipe-hide-bar'),
+ 'title' => isset($content_type['edit text']) ? $content_type['edit text'] : t('Settings'),
// 'id' => "pane-edit-panel-pane-$pane->pid",
),
);
}
+ // Add option to configure style in IPE
+ if (user_access('administer panels pane styles')) {
+ $vars['links']['style'] = array(
+ 'title' => '' . t('Style') . '',
+ 'href' => $renderer->get_url('style-type', 'pane', $pane->pid),
+ 'html' => TRUE,
+ 'attributes' => array(
+ 'class' => array('ctools-use-modal', 'panels-ipe-hide-bar'),
+ 'title' => t('Style'),
+ ),
+ );
+ }
+
// Deleting is managed entirely in the js; this is just an attachment point
// for it
- $links['delete'] = array(
- 'title' => t('Delete'),
+ $vars['links']['delete'] = array(
+ 'title' => '' . t('Delete') . '',
'href' => '#',
+ 'html' => TRUE,
'attributes' => array(
'class' => 'pane-delete',
'id' => "pane-delete-panel-pane-$pane->pid",
+ 'title' => t('Delete'),
),
);
+ $context = array(
+ 'pane' => $pane,
+ 'display' => $display,
+ 'renderer' => $renderer
+ );
+ drupal_alter('panels_ipe_pane_links', $vars['links'], $context);
+
+}
+
+function theme_panels_ipe_pane_wrapper($vars) {
+ $output = $vars['output'];
+ $pane = $vars['pane'];
+ $display = $vars['display'];
+
$attributes = array(
'class' => 'panels-ipe-linkbar',
);
- $links = theme('links', array('links' => $links, 'attributes' => $attributes));
+ $type = ctools_get_content_type($pane->type);
+ $title ='';
+
+ $links = theme('links', array('links' => $vars['links'], 'attributes' => $attributes));
+
if (!empty($pane->locks['type']) && $pane->locks['type'] == 'immovable') {
- $links .= '';
+ $links = '';
}
else {
- $links .= '';
+ $links = '';
}
+ $handlebar = '';
- $handlebar = '';
return $handlebar . $output;
}
function theme_panels_ipe_region_wrapper($vars) {
- return $vars['output'];
+ return $vars['controls'] . $vars['output'];
}
-function theme_panels_ipe_add_pane_button($vars) {
+function template_preprocess_panels_ipe_add_pane_button(&$vars) {
$region_id = $vars['region_id'];
$display = $vars['display'];
$renderer = $vars['renderer'];
+ $vars['links'] = '';
- $attributes = array('class' => 'ctools-use-modal');
- $link = l(t('Add new pane'), $renderer->get_url('select-content', $region_id), array('attributes' => $attributes));
- return '' . $link . '';
+ // Add option to configure style in IPE
+ if (user_access('administer panels region styles')) {
+ $vars['links']['style'] = array(
+ 'title' => '' . t('Region style') . '',
+ 'href' => $renderer->get_url('style-type', 'region', $region_id),
+ 'html' => TRUE,
+ 'attributes' => array(
+ 'class' => array('ctools-use-modal', 'panels-ipe-hide-bar', 'style'),
+ 'title' => t('Region style'),
+ ),
+ );
+ }
+
+ // Add option to add items in the IPE
+ $vars['links']['add-pane'] = array(
+ 'title' => '' . t('Add new pane') . '',
+ 'href' => $renderer->get_url('select-content', $region_id),
+ 'attributes' => array(
+ 'class' => array('ctools-use-modal', 'add', 'panels-ipe-hide-bar'),
+ 'title' => t('Add new pane'),
+ ),
+ 'html' => TRUE,
+ );
+
+ $context = array(
+ 'region_id' => $region_id,
+ 'display' => $display,
+ 'renderer' => $renderer,
+ );
+ drupal_alter('panels_ipe_region_links', $vars['links'], $context);
+
+}
+
+function theme_panels_ipe_add_pane_button($vars) {
+ $attributes = array(
+ 'class' => array('panels-ipe-linkbar', 'inline'),
+ );
+
+ $links = theme('links', array('links' => $vars['links'], 'attributes' => $attributes));
+
+ return '' . $links . '';
}
/**
@@ -151,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;
}
@@ -176,34 +247,27 @@ function panels_ipe_page_alter(&$page) {
function theme_panels_ipe_toolbar($vars) {
$buttons = $vars['buttons'];
+ ctools_include('cleanstring');
$output = "";
foreach ($buttons as $key => $ipe_buttons) {
+ $key = ctools_cleanstring($key);
$output .= "";
// Controls in this container will appear when the IPE is not on.
$output .= '';
// Controls in this container will appear when the IPE is on. It is usually
// filled via AJAX.
$output .= '';
-
+ $output .= '';
}
$output .= "";
return $output;
}
-
-function theme_panels_ipe_edit_button($vars) {
- $class = $vars['class'];
- $output = "";
-
- return $output;
-}
diff --git a/sites/all/modules/contrib/panels/panels/panels_ipe/plugins/display_renderers/ipe.inc b/sites/all/modules/contrib/panels/panels/panels_ipe/plugins/display_renderers/ipe.inc
old mode 100755
new mode 100644
diff --git a/sites/all/modules/contrib/panels/panels/panels_ipe/plugins/display_renderers/panels_renderer_ipe.class.php b/sites/all/modules/contrib/panels/panels/panels_ipe/plugins/display_renderers/panels_renderer_ipe.class.php
old mode 100755
new mode 100644
index 070378e7..470c4e2e
--- a/sites/all/modules/contrib/panels/panels/panels_ipe/plugins/display_renderers/panels_renderer_ipe.class.php
+++ b/sites/all/modules/contrib/panels/panels/panels_ipe/plugins/display_renderers/panels_renderer_ipe.class.php
@@ -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 "$output";
+ if ($this->access()) {
+ return "$output";
+ }
+ return $output;
}
function add_meta() {
+ if (!$this->access()) {
+ return parent::add_meta();
+ }
+
ctools_include('display-edit', 'panels');
ctools_include('content');
@@ -25,10 +57,46 @@ class panels_renderer_ipe extends panels_renderer_editor {
ctools_include('cleanstring');
$this->clean_key = ctools_cleanstring($this->display->cache_key);
- $button = theme('panels_ipe_edit_button', array('class' => 'panels-ipe-startedit', 'text' => t('Customize this page')));
- panels_ipe_toolbar_add_button($this->clean_key, 'panels-ipe-startedit', $button);
+ $button = array(
+ '#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'),
+ ),
+ '#ajax' => array(
+ 'progress' => 'throbber',
+ 'ipe_cache_key' => $this->clean_key,
+ ),
+ '#prefix' => '',
+ );
-// panels_ipe_get_cache_key($this->clean_key);
+ 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')) {
+ $button = array(
+ '#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'),
+ ),
+ '#ajax' => array(
+ 'progress' => 'throbber',
+ 'ipe_cache_key' => $this->clean_key,
+ ),
+
+ '#prefix' => '',
+ );
+
+ panels_ipe_toolbar_add_button($this->display->cache_key, 'panels-ipe-change-layout', $button);
+ }
ctools_include('ajax');
ctools_include('modal');
@@ -36,22 +104,16 @@ 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');
- $settings = array(
- 'formPath' => url($this->get_url('save-form')),
- );
drupal_add_js(array('PanelsIPECacheKeys' => array($this->clean_key)), 'setting');
- drupal_add_js(array('PanelsIPESettings' => array($this->clean_key => $settings)), 'setting');
drupal_add_library('system', 'ui.draggable');
drupal_add_library('system', 'ui.droppable');
drupal_add_library('system', 'ui.sortable');
-// drupal_add_js('misc/ui/jquery.ui.draggable.min.js');
-// drupal_add_js('misc/ui/jquery.ui.droppable.min.js');
-// drupal_add_js('misc/ui/jquery.ui.sortable.min.js');
-// jquery_ui_add(array('ui.draggable', 'ui.droppable', 'ui.sortable'));
+
parent::add_meta();
}
@@ -66,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') {
@@ -107,15 +172,36 @@ class panels_renderer_ipe extends panels_renderer_editor {
return "pid}\" class=\"panels-ipe-portlet-wrapper panels-ipe-portlet-marker\">" . $output . "";
}
+ 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);
+ $this->admin = FALSE;
+ }
+
function render_pane_content(&$pane) {
- $content = parent::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);
+ }
// Ensure that empty panes have some content.
- if (empty($content->content)) {
+ if (empty($content) || empty($content->content)) {
+ if (empty($content)) {
+ $content = new stdClass();
+ }
+
// Get the administrative title.
$content_type = ctools_get_content_type($pane->type);
$title = ctools_content_admin_title($content_type, $pane->subtype, $pane->configuration, $this->display->context);
- $content->content = t('Placeholder for empty "@title"', array('@title' => $title));
+ $content->content = t('Placeholder for empty or inaccessible "@title"', array('@title' => html_entity_decode($title, ENT_QUOTES)));
// Add these to prevent notices.
$content->type = 'panels_ipe';
$content->subtype = 'panels_ipe';
@@ -132,32 +218,31 @@ 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]));
// Wrap the placeholder in some guaranteed markup.
- $panes['empty_placeholder'] = '' . $empty_ph . "";
-
- // Generate this region's add new pane button. FIXME waaaaay too hardcoded
- $panes['add_button'] = theme('panels_ipe_add_pane_button', array('region_id' => $region_id, 'display' => $this->display, 'renderer' => $this));
+ $control = '' . $empty_ph . theme('panels_ipe_add_pane_button', array('region_id' => $region_id, 'display' => $this->display, 'renderer' => $this)) . "";
$output = parent::render_region($region_id, $panes);
- $output = theme('panels_ipe_region_wrapper', array('output' => $output, 'region_id' => $region_id, 'display' => $this->display, 'renderer' => $this));
+ $output = theme('panels_ipe_region_wrapper', array('output' => $output, 'region_id' => $region_id, 'display' => $this->display, 'controls' => $control, 'renderer' => $this));
$classes = 'panels-ipe-region';
- ctools_include('cleanstring');
- $region_id = ctools_cleanstring($region_id);
return "$output";
}
/**
- * AJAX entry point to create the controller form for an IPE.
+ * This is a generic lock test.
*/
- function ajax_save_form($break = NULL) {
+ function ipe_test_lock($url, $break) {
if (!empty($this->cache->locked)) {
if ($break != 'break') {
$account = user_load($this->cache->locked->uid);
- $name = theme('username', array('account' => $account));
+ $name = format_username($account);
$lock_age = format_interval(time() - $this->cache->locked->updated);
$message = t("This panel is being edited by user !user, and is therefore locked from editing by others. This lock is !age old.\n\nClick OK to break this lock and discard any changes made by !user.", array('!user' => $name, '!age' => $lock_age));
@@ -165,16 +250,60 @@ class panels_renderer_ipe extends panels_renderer_editor {
$this->commands[] = array(
'command' => 'unlockIPE',
'message' => $message,
- 'break_path' => url($this->get_url('save-form', 'break'))
+ 'break_path' => url($this->get_url($url, 'break')),
+ 'key' => $this->clean_key,
);
- return;
+ return TRUE;
}
// 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);
+ }
+
+ /**
+ * AJAX callback to unlock the IPE.
+ *
+ * This is called whenever something server side determines that editing
+ * has stopped and cleans up no longer needed locks.
+ *
+ * It has no visible return value as this is considered a background task
+ * and the client side has already given all indications that things are
+ * now in a 'normal' state.
+ */
+ function ajax_unlock_ipe() {
+ panels_edit_cache_clear($this->cache);
+ $this->commands[] = array();
+ }
+
+ /**
+ * AJAX entry point to create the controller form for an IPE.
+ */
+ function ajax_save_form($break = NULL) {
+ if ($this->ipe_test_lock('save-form', $break)) {
+ return;
+ }
+
+ // Reset the $_POST['ajax_html_ids'] values to preserve
+ // proper IDs on form elements when they are rebuilt
+ // by the Panels IPE without refreshing the page
+ $_POST['ajax_html_ids'] = array();
$form_state = array(
+ 'renderer' => $this,
'display' => &$this->display,
'content_types' => $this->cache->content_types,
'rerender' => FALSE,
@@ -186,11 +315,24 @@ class panels_renderer_ipe extends panels_renderer_editor {
$output = drupal_build_form('panels_ipe_edit_control_form', $form_state);
if (empty($form_state['executed'])) {
// At this point, we want to save the cache to ensure that we have a lock.
+ $this->cache->ipe_locked = TRUE;
panels_edit_cache_set($this->cache);
$this->commands[] = array(
'command' => 'initIPE',
'key' => $this->clean_key,
'data' => drupal_render($output),
+ 'lockPath' => url($this->get_url('unlock_ipe')),
+ );
+ return;
+ }
+
+ // Check to see if we have a lock that was broken. If so we need to
+ // inform the user and abort.
+ if (empty($this->cache->ipe_locked)) {
+ $this->commands[] = ajax_command_alert(t('A lock you had has been externally broken, and all your changes have been reverted.'));
+ $this->commands[] = array(
+ 'command' => 'cancelIPE',
+ 'key' => $this->clean_key,
);
return;
}
@@ -199,6 +341,13 @@ 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);
+ // A rerender should fix IDs on added panes as well as ensure style changes are
+ // 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.
@@ -208,10 +357,97 @@ class panels_renderer_ipe extends panels_renderer_editor {
$this->commands[] = array(
'command' => 'endIPE',
'key' => $this->clean_key,
- 'data' => $output,
);
}
+ /**
+ * AJAX entry point to create the controller form for an IPE.
+ */
+ function ajax_change_layout($break = NULL) {
+ if ($this->ipe_test_lock('change_layout', $break)) {
+ return;
+ }
+
+ // At this point, we want to save the cache to ensure that we have a lock.
+ $this->cache->ipe_locked = TRUE;
+ panels_edit_cache_set($this->cache);
+
+ ctools_include('plugins', 'panels');
+ ctools_include('common', 'panels');
+
+ // @todo figure out a solution for this, it's critical
+ if (isset($this->display->allowed_layouts)) {
+ $layouts = $this->display->allowed_layouts;
+ }
+ else {
+ $layouts = panels_common_get_allowed_layouts('panels_page');
+ }
+
+ // 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'];
+
+ $output = panels_common_print_layout_links($layouts, $this->get_url('set_layout'), array('attributes' => array('class' => array('use-ajax'))), $current_layout);
+
+ $this->commands[] = ctools_modal_command_display(t('Change layout'), $output);
+ $this->commands[] = array(
+ 'command' => 'IPEsetLockState',
+ 'key' => $this->clean_key,
+ 'lockPath' => url($this->get_url('unlock_ipe')),
+ );
+ }
+
+ function ajax_set_layout($layout) {
+ ctools_include('context');
+ ctools_include('display-layout', 'panels');
+ $form_state = array(
+ 'layout' => $layout,
+ 'display' => $this->display,
+ 'finish' => t('Save'),
+ 'no_redirect' => TRUE,
+ );
+
+ // Reset the $_POST['ajax_html_ids'] values to preserve
+ // proper IDs on form elements when they are rebuilt
+ // by the Panels IPE without refreshing the page
+ $_POST['ajax_html_ids'] = array();
+
+ $output = drupal_build_form('panels_change_layout', $form_state);
+ $output = drupal_render($output);
+ if (!empty($form_state['executed'])) {
+ if (isset($form_state['back'])) {
+ return $this->ajax_change_layout();
+ }
+
+ if (!empty($form_state['clicked_button']['#save-display'])) {
+ // Saved. Save the cache.
+ panels_edit_cache_save($this->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.
+ $layout = panels_get_layout($this->display->layout);
+ $this->plugins['layout'] = $layout;
+ if (!isset($layout['regions'])) {
+ $this->plugins['layout']['regions'] = panels_get_regions($layout, $this->display);
+ }
+
+ $this->meta_location = 'inline';
+
+ $this->commands[] = ajax_command_replace("#panels-ipe-display-{$this->clean_key}", panels_render_display($this->display, $this));
+ $this->commands[] = ctools_modal_command_dismiss();
+ return;
+ }
+ }
+
+ $this->commands[] = ctools_modal_command_display(t('Change layout'), $output);
+ }
+
/**
* Create a command array to redraw a pane.
*/
@@ -238,10 +474,16 @@ class panels_renderer_ipe extends panels_renderer_editor {
$pane = $this->display->content[$pid];
}
- ctools_include('cleanstring');
- $region_id = ctools_cleanstring($pane->panel);
- $this->commands[] = ajax_command_append("#panels-ipe-regionid-$region_id 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',
+ 'key' => $this->clean_key,
+ );
}
}
@@ -279,12 +521,14 @@ function panels_ipe_edit_control_form($form, &$form_state) {
'#type' => 'submit',
'#value' => t('Save'),
'#id' => 'panels-ipe-save',
+ '#attributes' => array('class' => array('panels-ipe-save')),
'#submit' => array('panels_edit_display_form_submit'),
'#save-display' => TRUE,
);
$form['buttons']['cancel'] = array(
'#type' => 'submit',
'#id' => 'panels-ipe-cancel',
+ '#attributes' => array('class' => array('panels-ipe-cancel')),
'#value' => t('Cancel'),
);
return $form;
diff --git a/sites/all/modules/contrib/panels/panels/panels_mini/panels_mini.css b/sites/all/modules/contrib/panels/panels/panels_mini/panels_mini.css
new file mode 100644
index 00000000..246921c5
--- /dev/null
+++ b/sites/all/modules/contrib/panels/panels/panels_mini/panels_mini.css
@@ -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;
+}
diff --git a/sites/all/modules/contrib/panels/panels/panels_mini/panels_mini.info b/sites/all/modules/contrib/panels/panels/panels_mini/panels_mini.info
old mode 100755
new mode 100644
index 59822f1e..49558562
--- a/sites/all/modules/contrib/panels/panels/panels_mini/panels_mini.info
+++ b/sites/all/modules/contrib/panels/panels/panels_mini/panels_mini.info
@@ -4,9 +4,9 @@ package = "Panels"
dependencies[] = panels
core = 7.x
files[] = plugins/export_ui/panels_mini_ui.class.php
-; Information added by drupal.org packaging script on 2012-01-18
-version = "7.x-3.0"
+; Information added by Drupal.org packaging script on 2016-10-16
+version = "7.x-3.8"
core = "7.x"
project = "panels"
-datestamp = "1326917446"
+datestamp = "1476582295"
diff --git a/sites/all/modules/contrib/panels/panels/panels_mini/panels_mini.install b/sites/all/modules/contrib/panels/panels/panels_mini/panels_mini.install
old mode 100755
new mode 100644
index 7313d4b5..b3239dde
--- a/sites/all/modules/contrib/panels/panels/panels_mini/panels_mini.install
+++ b/sites/all/modules/contrib/panels/panels/panels_mini/panels_mini.install
@@ -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');
+ }
+}
diff --git a/sites/all/modules/contrib/panels/panels/panels_mini/panels_mini.module b/sites/all/modules/contrib/panels/panels/panels_mini/panels_mini.module
old mode 100755
new mode 100644
index 4ced56ad..2139de1c
--- a/sites/all/modules/contrib/panels/panels/panels_mini/panels_mini.module
+++ b/sites/all/modules/contrib/panels/panels/panels_mini/panels_mini.module
@@ -62,7 +62,7 @@ function panels_mini_settings() {
// Allow the rest of the system access to mini panels
/**
- * Implementation of hook_block_list().
+ * Implementation of hook_block_info().
*/
function panels_mini_block_info() {
// Safety: go away if CTools is not at an appropriate version.
@@ -74,7 +74,7 @@ function panels_mini_block_info() {
$minis = panels_mini_load_all();
foreach ($minis as $panel_mini) {
- if (empty($panel_mini->disabled) && empty($panel_mini->requiredcontext)) {
+ if (empty($panel_mini->disabled) && (module_exists('page_manager') || empty($panel_mini->requiredcontexts))) {
$blocks[$panel_mini->name] = array(
'info' => t('Mini panel: "@title"', array('@title' => $panel_mini->admin_title)),
'cache' => DRUPAL_NO_CACHE,
@@ -87,6 +87,8 @@ function panels_mini_block_info() {
/**
* Implementation of hook_block_view().
+ *
+ * @see panels_mini_panels_mini_content_type_render().
*/
function panels_mini_block_view($delta = 0) {
// static recursion protection.
@@ -103,8 +105,18 @@ function panels_mini_block_view($delta = 0) {
}
ctools_include('context');
- $panel_mini->context = $panel_mini->display->context = ctools_context_load_contexts($panel_mini);
+
+ $contexts = array();
+ if (module_exists('page_manager') && $current_page = page_manager_get_current_page()) {
+ if (!empty($current_page['contexts'])) {
+ $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();
@@ -120,12 +132,96 @@ function panels_mini_block_view($delta = 0) {
*/
function panels_mini_block_configure($delta = 0) {
return array(
- 'admin-shortcut' => array(
- '#value' => l(t('Manage this mini-panel'), 'admin/structure/mini-panels/' . $delta . '/edit')
+ 'admin_shortcut' => array(
+ '#markup' => l(t('Manage this mini-panel'), 'admin/structure/mini-panels/list/' . $delta . '/edit')
),
);
}
+/**
+ * Implements hook_block_list_alter().
+ *
+ * Remove the block if the required contexts are not available.
+ */
+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.
+ continue;
+ }
+
+ $panel_mini = panels_mini_load($block->delta);
+ if (empty($panel_mini)) {
+ // Bail out early if the specified mini panel doesn't exist.
+ unset($blocks[$key]);
+ continue;
+ }
+
+ if (!empty($panel_mini->requiredcontexts)) {
+ if (!$current_page || empty($current_page['contexts'])) {
+ unset($blocks[$key]);
+ continue;
+ }
+ else {
+ $required = array();
+ foreach ($panel_mini->requiredcontexts as $context) {
+ $info = ctools_get_context($context['name']);
+ $required[] = new ctools_context_required($context['identifier'], $info['context name']);
+ }
+ if (!ctools_context_match_requirements($current_page['contexts'], $required)) {
+ unset($blocks[$key]);
+ continue;
+ }
+ }
+ }
+ }
+}
+
+/**
+ * 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.
*/
@@ -163,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;
+ }
}
}
@@ -201,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');
@@ -233,7 +353,8 @@ function panels_mini_load_all($reset = FALSE) {
}
}
- return $cache;
+ // Strip out NULL entries that may have been added by panels_mini_load().
+ return array_filter($cache);
}
/**
@@ -241,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);
@@ -259,7 +384,7 @@ function panels_mini_delete($mini) {
->condition('name', $mini->name)
->execute();
- if ($mini->type != t('Overridden')) {
+ if (db_table_exists('block') && $mini->type != t('Overridden')) {
// Also remove from block table as long as there isn't a default that may appear.
db_delete('block')
->condition('delta', $mini->name)
@@ -297,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;
+ }
+ }
}
/**
@@ -335,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;
@@ -378,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().
*
@@ -427,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');
+}
diff --git a/sites/all/modules/contrib/panels/panels/panels_mini/plugins/content_types/icon_panels_mini.png b/sites/all/modules/contrib/panels/panels/panels_mini/plugins/content_types/icon_panels_mini.png
old mode 100755
new mode 100644
diff --git a/sites/all/modules/contrib/panels/panels/panels_mini/plugins/content_types/panels_mini.inc b/sites/all/modules/contrib/panels/panels/panels_mini/plugins/content_types/panels_mini.inc
old mode 100755
new mode 100644
index 6bd4d94b..2d092bed
--- a/sites/all/modules/contrib/panels/panels/panels_mini/plugins/content_types/panels_mini.inc
+++ b/sites/all/modules/contrib/panels/panels/panels_mini/plugins/content_types/panels_mini.inc
@@ -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;
@@ -109,6 +114,16 @@ function panels_mini_panels_mini_content_type_render($subtype, $conf, $panel_arg
$block->content = panels_render_display($mini->display);
$block->title = $mini->display->get_title();
+ if (user_access('administer mini panels')) {
+ $block->admin_links = array(
+ array(
+ 'title' => t('Configure mini panel'),
+ 'href' => "admin/structure/mini-panels/list/$subtype/edit/content",
+ 'query' => drupal_get_destination(),
+ ),
+ );
+ }
+
unset($viewing[$mini->name]);
return $block;
}
@@ -137,3 +152,30 @@ function panels_mini_panels_mini_content_type_admin_title($subtype, $conf) {
return $title;
}
+/**
+ * Callback to provide administrative info. Provide links to edit the mini
+ * panel.
+ */
+function panels_mini_panels_mini_content_type_admin_info($subtype, $conf) {
+ $mini = panels_mini_load($subtype);
+ if (!$mini) {
+ return FALSE;
+ }
+
+ $block = new stdClass();
+ $block->title = $mini->admin_title;
+ $admin_pages = array(
+ t('Settings') => 'basic',
+ t('Context') => 'context',
+ t('Layout') => 'layout',
+ t('Content') => 'content',
+ );
+
+ $links = array();
+ foreach ($admin_pages as $title => $tail) {
+ $links[] = l($title, 'admin/structure/mini-panels/list/' . $subtype . '/edit/' . $tail, array('query' => drupal_get_destination()));
+ }
+
+ $block->content = theme('item_list', array('items' => $links));
+ return $block;
+}
diff --git a/sites/all/modules/contrib/panels/panels/panels_mini/plugins/export_ui/panels_mini.inc b/sites/all/modules/contrib/panels/panels/panels_mini/plugins/export_ui/panels_mini.inc
old mode 100755
new mode 100644
diff --git a/sites/all/modules/contrib/panels/panels/panels_mini/plugins/export_ui/panels_mini_ui.class.php b/sites/all/modules/contrib/panels/panels/panels_mini/plugins/export_ui/panels_mini_ui.class.php
old mode 100755
new mode 100644
index 6c7d0845..cff8fe63
--- a/sites/all/modules/contrib/panels/panels/panels_mini/plugins/export_ui/panels_mini_ui.class.php
+++ b/sites/all/modules/contrib/panels/panels/panels_mini/plugins/export_ui/panels_mini_ui.class.php
@@ -118,6 +118,13 @@ class panels_mini_ui extends ctools_export_ui {
// Get the basic edit form
parent::edit_form($form, $form_state);
+ // Set the admin title machine name length.
+ // We need to do this because the system block name length is
+ // limited to 32 chars.
+ $form['info']['name']['#maxlength'] = 32;
+ $form['info']['name']['#size'] = 34;
+ $form['info']['name']['#description'] .= ' ' . t('The machine name length is limited to 32 characters, due to a limitation in the core block system.');
+
$form['category'] = array(
'#type' => 'textfield',
'#size' => 24,
diff --git a/sites/all/modules/contrib/panels/panels/panels_mini/plugins/panels_storage/panels_mini.inc b/sites/all/modules/contrib/panels/panels/panels_mini/plugins/panels_storage/panels_mini.inc
new file mode 100644
index 00000000..c9ba35d7
--- /dev/null
+++ b/sites/all/modules/contrib/panels/panels/panels_mini/plugins/panels_storage/panels_mini.inc
@@ -0,0 +1,22 @@
+ '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);
+}
diff --git a/sites/all/modules/contrib/panels/panels/panels_node/panels_node.info b/sites/all/modules/contrib/panels/panels/panels_node/panels_node.info
old mode 100755
new mode 100644
index 03446584..98bf72db
--- a/sites/all/modules/contrib/panels/panels/panels_node/panels_node.info
+++ b/sites/all/modules/contrib/panels/panels/panels_node/panels_node.info
@@ -6,9 +6,9 @@ configure = admin/structure/panels
core = 7.x
files[] = panels_node.module
-; Information added by drupal.org packaging script on 2012-01-18
-version = "7.x-3.0"
+; Information added by Drupal.org packaging script on 2016-10-16
+version = "7.x-3.8"
core = "7.x"
project = "panels"
-datestamp = "1326917446"
+datestamp = "1476582295"
diff --git a/sites/all/modules/contrib/panels/panels/panels_node/panels_node.install b/sites/all/modules/contrib/panels/panels/panels_node/panels_node.install
old mode 100755
new mode 100644
index c68e40d0..1af682fc
--- a/sites/all/modules/contrib/panels/panels/panels_node/panels_node.install
+++ b/sites/all/modules/contrib/panels/panels/panels_node/panels_node.install
@@ -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');
+ }
+}
diff --git a/sites/all/modules/contrib/panels/panels/panels_node/panels_node.module b/sites/all/modules/contrib/panels/panels/panels_node/panels_node.module
old mode 100755
new mode 100644
index 4044c5a5..bc9d56f9
--- a/sites/all/modules/contrib/panels/panels/panels_node/panels_node.module
+++ b/sites/all/modules/contrib/panels/panels/panels_node/panels_node.module
@@ -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)) {
@@ -339,6 +322,7 @@ function panels_node_hook_view($node, $view_mode) {
$display->css_id = $node->panels_node['css_id'];
// TODO: Find a way to make sure this can't node_view.
$display->context = panels_node_get_context($node);
+ $display->cache_key = 'panels_node:' . $node->nid;
$renderer = panels_get_renderer($node->panels_node['pipeline'], $display);
$node->content['body'] = array(
'#markup' => panels_render_display($display, $renderer),
@@ -429,3 +413,72 @@ function panels_node_panels_dashboard_blocks(&$vars) {
'weight' => -1,
);
}
+
+/**
+ * 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.
+
+/**
+ * Get display edit cache for a panel node being edited.
+ *
+ * The key is the second half of the key in this form:
+ * panels_node:NID;
+ */
+function panels_node_panels_cache_get($nid) {
+ ctools_include('object-cache');
+ $cache = ctools_object_cache_get('panels_node_display_cache', $nid);
+ if (empty($cache)) {
+ $cache = new stdClass();
+ $node = node_load($nid);
+ if (empty($node)) {
+ return;
+ }
+
+ ctools_include('common', 'panels');
+ $cache->display = panels_load_display($node->panels_node['did']);
+ $cache->display->css_id = $node->panels_node['css_id'];
+ $cache->display->context = panels_node_get_context($node);
+ $cache->display->cache_key = 'panels_node:' . $node->nid;
+ $cache->content_types = panels_common_get_allowed_types('panels_node', $cache->display->context);
+ $cache->allwed_layouts = panels_common_get_allowed_layouts('panels_node');
+ }
+
+ return $cache;
+}
+
+/**
+ * Store a display edit in progress in the panels cache.
+ */
+function panels_node_panels_cache_set($nid, $cache) {
+ ctools_include('object-cache');
+ ctools_object_cache_set('panels_node_display_cache', $nid, $cache);
+}
+
+/**
+ * Clear all changes made to a display using the panels cache.
+ */
+function panels_node_panels_cache_clear($nid, $cache) {
+ ctools_include('object-cache');
+ ctools_object_cache_clear('panels_node_display_cache', $nid);
+}
+
+/**
+ * React to a cache save and save the display and clear cache.
+ */
+function panels_node_panels_cache_save($nid, $cache) {
+ panels_save_display($cache->display);
+ ctools_include('object-cache');
+ ctools_object_cache_clear('panels_node_display_cache', $nid);
+}
diff --git a/sites/all/modules/contrib/panels/panels/panels_node/plugins/panels_storage/panels_node.inc b/sites/all/modules/contrib/panels/panels/panels_node/plugins/panels_storage/panels_node.inc
new file mode 100644
index 00000000..a7a7a3b2
--- /dev/null
+++ b/sites/all/modules/contrib/panels/panels/panels_node/plugins/panels_storage/panels_node.inc
@@ -0,0 +1,25 @@
+ '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;
+}
diff --git a/sites/all/modules/contrib/panels/panels/plugins/cache/simple.inc b/sites/all/modules/contrib/panels/panels/plugins/cache/simple.inc
new file mode 100644
index 00000000..6b76678c
--- /dev/null
+++ b/sites/all/modules/contrib/panels/panels/plugins/cache/simple.inc
@@ -0,0 +1,161 @@
+ t("Simple cache"),
+ 'description' => t('Simple caching is a time-based cache. This is a hard limit, and once cached it will remain that way until the time limit expires.'),
+ 'cache get' => 'panels_simple_cache_get_cache',
+ 'cache set' => 'panels_simple_cache_set_cache',
+ 'cache clear' => 'panels_simple_cache_clear_cache',
+ 'settings form' => 'panels_simple_cache_settings_form',
+ 'settings form submit' => 'panels_simple_cache_settings_form_submit',
+ 'defaults' => array(
+ 'lifetime' => 15,
+ 'granularity' => 'none',
+ ),
+);
+
+/**
+ * Get cached content.
+ */
+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_panels');
+ if (!$cache) {
+ return FALSE;
+ }
+
+ if ((time() - $cache->created) > $conf['lifetime']) {
+ return FALSE;
+ }
+
+ return $cache->data;
+}
+
+/**
+ * Set cached content.
+ */
+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_panels');
+}
+
+/**
+ * Clear cached content.
+ *
+ * Cache clears are always for an entire display, regardless of arguments.
+ */
+function panels_simple_cache_clear_cache($display) {
+ $cid = 'panels_simple_cache';
+
+ // 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;
+ }
+
+ cache_clear_all($cid, 'cache_panels', TRUE);
+}
+
+/**
+ * Figure out an id for our cache based upon input and settings.
+ */
+function panels_simple_cache_get_id($conf, $display, $args, $contexts, $pane) {
+ $id = 'panels_simple_cache';
+
+ // If the panel is stored in the database it'll have a numeric did value.
+ if (is_numeric($display->did)) {
+ $id .= ':' . $display->did;
+ }
+ // Exported panels won't have a numeric did but may have a usable cache_key.
+ elseif (!empty($display->cache_key)) {
+ $id .= ':' . str_replace('panel_context:', '', $display->cache_key);
+ }
+ // Alternatively use the css_id.
+ elseif (!empty($display->css_id)) {
+ $id .= ':' . $display->css_id;
+ }
+ // Failover to just appending the did, which may be the completely unusable
+ // string 'new'.
+ else {
+ $id .= ':' . $display->did;
+ }
+
+ if ($pane) {
+ $id .= ':' . $pane->pid;
+ }
+
+ if (user_access('view pane admin links')) {
+ $id .= ':admin';
+ }
+
+ switch ($conf['granularity']) {
+ case 'args':
+ foreach ($args as $arg) {
+ $id .= ':' . $arg;
+ }
+ break;
+
+ case 'context':
+ if (!is_array($contexts)) {
+ $contexts = array($contexts);
+ }
+ foreach ($contexts as $context) {
+ if (isset($context->argument)) {
+ $id .= ':' . $context->argument;
+ }
+ }
+ }
+ if (module_exists('locale')) {
+ global $language;
+ $id .= ':' . $language->language;
+ }
+
+ if(!empty($pane->configuration['use_pager']) && !empty($_GET['page'])) {
+ $id .= ':p' . check_plain($_GET['page']);
+ }
+
+ return $id;
+}
+
+function panels_simple_cache_settings_form($conf, $display, $pid) {
+ $options = drupal_map_assoc(array(15, 30, 60, 120, 180, 240, 300, 600, 900, 1200, 1800, 3600, 7200, 14400, 28800, 43200, 86400, 172800, 259200, 345600, 604800), 'format_interval');
+ $form['lifetime'] = array(
+ '#title' => t('Lifetime'),
+ '#type' => 'select',
+ '#options' => $options,
+ '#default_value' => $conf['lifetime'],
+ );
+
+ $form['granularity'] = array(
+ '#title' => t('Granularity'),
+ '#type' => 'select',
+ '#options' => array(
+ 'args' => t('Arguments'),
+ 'context' => t('Context'),
+ 'none' => t('None'),
+ ),
+ '#description' => t('If "arguments" are selected, this content will be cached per individual argument to the entire display; if "contexts" are selected, this content will be cached per unique context in the pane or display; if "neither" there will be only one cache for this pane.'),
+ '#default_value' => $conf['granularity'],
+ );
+
+ return $form;
+}
+
diff --git a/sites/all/modules/contrib/panels/panels/plugins/display_renderers/editor.inc b/sites/all/modules/contrib/panels/panels/plugins/display_renderers/editor.inc
old mode 100755
new mode 100644
diff --git a/sites/all/modules/contrib/panels/panels/plugins/display_renderers/panels_renderer_editor.class.php b/sites/all/modules/contrib/panels/panels/plugins/display_renderers/panels_renderer_editor.class.php
old mode 100755
new mode 100644
index 4fee7e37..0d3dfa6b
--- a/sites/all/modules/contrib/panels/panels/plugins/display_renderers/panels_renderer_editor.class.php
+++ b/sites/all/modules/contrib/panels/panels/plugins/display_renderers/panels_renderer_editor.class.php
@@ -13,6 +13,13 @@ class panels_renderer_editor extends panels_renderer_standard {
*/
var $commands = array();
var $admin = TRUE;
+
+ /**
+ * Set to true if edit links (for panes and regions) should not be displayed.
+ * This can be used for special edit modes such as layout change and layout
+ * builder that do not actually have real content.
+ */
+ var $no_edit_links = FALSE;
// -------------------------------------------------------------------------
// Display edit rendering.
@@ -54,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');
}
}
@@ -146,7 +154,7 @@ class panels_renderer_editor extends panels_renderer_standard {
$output = '';
- if (!$block->title) {
+ if (empty($block->title)) {
$block->title = t('No title');
}
@@ -154,7 +162,7 @@ class panels_renderer_editor extends panels_renderer_standard {
if ($buttons) {
$output .= '';
}
- $output .= '' . $title . '';
+ $output .= '' . $title . '';
$output .= ''; // grabber
$output .= '';
@@ -179,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')),
@@ -192,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')),
@@ -210,7 +218,7 @@ class panels_renderer_editor extends panels_renderer_standard {
function get_display_links() {
$links = array();
- if (user_access('administer panels styles')) {
+ if (user_access('administer panels display styles')) {
$style_links = $this->get_style_links('display');
$links[] = array(
'title' => '' . t('Style') . '' . theme_links(array('links' => $style_links, 'attributes' => array(), 'heading' => array())),
@@ -260,6 +268,9 @@ class panels_renderer_editor extends panels_renderer_standard {
* Render the links to display when editing a region.
*/
function get_region_links($region_id) {
+ if (!empty($this->no_edit_links)) {
+ return '';
+ }
$links = array();
$links[] = array(
'title' => t('Add content'),
@@ -269,7 +280,7 @@ class panels_renderer_editor extends panels_renderer_standard {
),
);
- if (user_access('administer panels styles')) {
+ if (user_access('administer panels region styles')) {
$links[] = array(
'title' => '
',
'html' => TRUE,
@@ -291,17 +302,20 @@ class panels_renderer_editor extends panels_renderer_standard {
* Render the links to display when editing a pane.
*/
function get_pane_links($pane, $content_type) {
+ if (!empty($this->no_edit_links)) {
+ return '';
+ }
$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')),
@@ -309,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('✓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')),
@@ -325,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')),
@@ -333,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')),
@@ -341,26 +355,10 @@ class panels_renderer_editor extends panels_renderer_standard {
}
if (user_access('administer panels styles')) {
- $links[] = array(
- 'title' => '
',
- 'html' => TRUE,
- );
-
- $style_links = $this->get_style_links('pane', $pane->pid);
-
- $links[] = array(
- 'title' => '' . t('Style') . '' . 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' => '
',
- 'html' => TRUE,
- );
-
$contexts = $this->display->context;
// Make sure we have the logged in user context
if (!isset($contexts['logged-in-user'])) {
@@ -372,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(
@@ -383,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' => '' . t('Visibility rules') . '' . 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' => '
',
- 'html' => TRUE,
- );
-
$lock_type = !empty($pane->locks['type']) ? $pane->locks['type'] : 'none';
switch ($lock_type) {
case 'immovable':
@@ -428,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' => '' . t('Locking') . '' . 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' => '
',
- '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' => '' . t('Caching') . '' . 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' => '
',
- 'html' => TRUE,
- );
-
- $links[] = array(
+ $links['bottom']['remove'] = array(
'title' => t('Remove'),
'href' => '#',
'attributes' => array(
@@ -492,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' => '
',
+ 'html' => TRUE,
+ );
+ $dropdown_links[] = array(
+ 'title' => '' . t($label) . '' . theme_links(array('links' => $links[$category], 'attributes' => array(), 'heading' => array())),
+ 'html' => TRUE,
+ 'attributes' => array('class' => array('panels-sub-menu')),
+ );
+ }
+ }
+
+ $dropdown_links[] = array(
+ 'title' => '
',
+ '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));
}
// -----------------------------------------------------------------------
@@ -512,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.
*/
@@ -556,19 +592,14 @@ class panels_renderer_editor extends panels_renderer_standard {
$output = t('There are no content types you may add to this display.');
}
else {
- $output = '';
- $selector = $this->render_category_selector($categories, $category, $region);
-
- $content = !empty($categories[$category]['content']) ? $categories[$category]['content'] : array();
- $center = $this->render_category($content, $category, $region);
-
- $output .= ''
- . '' . $selector . '';
- $output .= $center;
- $output .= ''; // panels-add-content-modal
+ $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');
+ }
}
/**
@@ -578,7 +609,7 @@ class panels_renderer_editor extends panels_renderer_standard {
* @todo -- this should be in CTools.
*/
function get_category($content_type) {
- if (isset($content_type['top level'])) {
+ if (!empty($content_type['top level'])) {
$category = 'root';
}
else if (isset($content_type['category'])) {
@@ -646,94 +677,6 @@ class panels_renderer_editor extends panels_renderer_standard {
return $output;
}
- /**
- * Render a single link to add a content type.
- */
- function render_add_content_link($region, $content_type) {
- $title = filter_xss_admin($content_type['title']);
- $description = isset($content_type['description']) ? $content_type['description'] : $title;
- $icon = ctools_content_admin_icon($content_type);
- $url = $this->get_url('add-pane', $region, $content_type['type_name'], $content_type['subtype_name']);
-
- $output = '';
-
- return $output;
- }
-
- /**
- * Render the selector widget in the add content modal to select categories.
- */
- function render_category_selector($categories, $category, $region) {
- $output = '';
-
- // Render our list of categories in column 0.
- foreach ($categories as $key => $category_info) {
- if ($key == 'root') {
- continue;
- }
-
- $class = 'panels-modal-add-category';
- if ($key == $category) {
- $class .= ' active';
- }
-
- $url = $this->get_url('select-content', $region, $key);
- $output .= ctools_ajax_text_button($category_info['title'], $url, '', $class);
- }
-
- $output .= ''; // panels-categories-box
-
- if (!empty($categories['root'])) {
- foreach ($categories['root']['content'] as $content_type) {
- $output .= $this->render_add_content_link($region, $content_type);
- }
- }
-
- return $output;
- }
-
- /**
- * Render all of the content links in a category.
- */
- function render_category($content, $category, $region) {
- if (empty($category) || empty($content) || $category == 'root') {
- $output = '';
- $output .= t('Content options are divided by category. Please select a category from the left to proceed.');
- $output .= '';
- }
- else {
- $titles = array_keys($content);
- natcasesort($titles);
-
- // Fill out the info for our current category.
- $columns = 2;
- $col[1] = '';
- $col[2] = '';
-
- $col_size = count($titles) / $columns;
- $count = 0;
- foreach ($titles as $title) {
- $which = floor($count++ / $col_size) + 1; // we leave 0 for the categories.
- $col[$which] .= $this->render_add_content_link($region, $content[$title]);
- }
-
- $output = '';
- foreach ($col as $id => $column) {
- $output .= ''
- . '' . $column . '';
- }
- $output .= ''; // columns
- }
-
- if ($messages = theme('status_messages')) {
- $output = '' . $output;
- }
- return $output;
- }
-
/**
* AJAX entry point to add a new pane.
*/
@@ -741,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;
}
@@ -842,6 +797,11 @@ class panels_renderer_editor extends panels_renderer_standard {
// References get blown away with AJAX caching. This will fix that.
$this->cache->display->content[$pid] = $form_state['pane'];
+ // Conditionally overwrite the context for this panel if present in the form state.
+ if (!empty($form_state['display_cache']->display->context)) {
+ $this->cache->display->context = $form_state['display_cache']->display->context;
+ }
+
panels_edit_cache_set($this->cache);
$this->command_update_pane($pid);
$this->commands[] = ctools_modal_command_dismiss();
@@ -1027,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:
@@ -1047,6 +1010,7 @@ class panels_renderer_editor extends panels_renderer_standard {
$form_state = array(
'display' => &$this->display,
'style' => $style,
+ 'pane' => ($type == 'pane') ? $this->display->content[$pid] : NULL,
'title' => $title,
'ajax' => TRUE,
'type' => $type,
@@ -1242,7 +1206,23 @@ class panels_renderer_editor extends panels_renderer_standard {
unset($this->cache->style);
}
- // $conf was a reference so it should just modify.
+ 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'])) {
+ 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);
$this->commands[] = ctools_modal_command_dismiss();
@@ -1560,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.
@@ -1585,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'];
@@ -1633,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'];
@@ -1693,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'];
@@ -1743,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'];
@@ -1767,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.
*/
@@ -1797,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'];
@@ -1804,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(
@@ -1839,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'];
@@ -1914,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'];
@@ -1951,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'];
@@ -1980,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'];
diff --git a/sites/all/modules/contrib/panels/panels/plugins/display_renderers/panels_renderer_simple.class.php b/sites/all/modules/contrib/panels/panels/plugins/display_renderers/panels_renderer_simple.class.php
old mode 100755
new mode 100644
diff --git a/sites/all/modules/contrib/panels/panels/plugins/display_renderers/panels_renderer_standard.class.php b/sites/all/modules/contrib/panels/panels/plugins/display_renderers/panels_renderer_standard.class.php
old mode 100755
new mode 100644
index 471c0e04..58a72ee6
--- a/sites/all/modules/contrib/panels/panels/plugins/display_renderers/panels_renderer_standard.class.php
+++ b/sites/all/modules/contrib/panels/panels/plugins/display_renderers/panels_renderer_standard.class.php
@@ -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.
*
@@ -167,7 +176,7 @@ class panels_renderer_standard {
$layout = panels_get_layout($display->layout);
$this->display = &$display;
$this->plugins['layout'] = $layout;
- if (!isset($layout['panels'])) {
+ if (!isset($layout['regions'])) {
$this->plugins['layout']['regions'] = panels_get_regions($layout, $display);
}
@@ -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.
*
@@ -231,7 +253,15 @@ class panels_renderer_standard {
}
}
- $content_type = ctools_get_content_type($pane->type);
+ // If the pane's subtype is unique, get it so that
+ // hook_ctools_content_subtype_alter() and/or
+ // hook_ctools_block_info() will be called.
+ if ($pane->type != $pane->subtype) {
+ $content_type = ctools_content_get_subtype($pane->type, $pane->subtype);
+ }
+ else {
+ $content_type = ctools_get_content_type($pane->type);
+ }
// If this pane wants to render last, add it to the $last array. We allow
// this because some panes need to be rendered after other panes,
@@ -251,6 +281,10 @@ class panels_renderer_standard {
}
}
$this->prepared['panes'] = $first + $normal + $last;
+
+ // Allow other modules the alter the prepared panes array.
+ drupal_alter('panels_panes_prepared', $this->prepared['panes'], $this);
+
return $this->prepared['panes'];
}
@@ -311,7 +345,6 @@ class panels_renderer_standard {
foreach ($this->plugins['layout']['regions'] as $region_id => $title) {
// Ensure this region has at least an empty panes array.
$panes = !empty($region_pane_list[$region_id]) ? $region_pane_list[$region_id] : array();
-
if (empty($settings[$region_id]['style']) || $settings[$region_id]['style'] == -1) {
$regions[$region_id] = $default;
}
@@ -385,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;
}
@@ -396,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);
+ }
}
}
@@ -423,20 +493,13 @@ class panels_renderer_standard {
* @see drupal_add_css
*/
function add_css($filename) {
-// $path = file_create_path($filename);
switch ($this->meta_location) {
case 'standard':
drupal_add_css($filename);
break;
case 'inline':
-// if ($path) {
-// $url = file_create_url($filename);
-// }
-// else {
- $url = base_path() . $filename;
-// }
-
- $this->prefix .= ''."\n";
+ $url = base_path() . $filename;
+ $this->prefix .= ''."\n";
break;
}
}
@@ -449,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.
@@ -473,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) {
@@ -526,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;
@@ -540,13 +605,9 @@ 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);
+ $function($content, $pane, $this->display->args, $this->display->context, $this, $this->display);
}
if ($caching && isset($cache)) {
$cache->set_content($content);
@@ -555,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;
@@ -576,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
@@ -623,6 +690,7 @@ class panels_renderer_standard {
$owner_id = $this->display->owner->id;
}
- return theme($style['render region'], array('display' => $this->display, 'owner_id' => $owner_id, 'panes' => $panes, 'settings' => $style_settings, 'region_id' => $region_id, 'style' => $style));
+ $output = theme($style['render region'], array('display' => $this->display, 'owner_id' => $owner_id, 'panes' => $panes, 'settings' => $style_settings, 'region_id' => $region_id, 'style' => $style));
+ return $output;
}
}
diff --git a/sites/all/modules/contrib/panels/panels/plugins/display_renderers/simple.inc b/sites/all/modules/contrib/panels/panels/plugins/display_renderers/simple.inc
old mode 100755
new mode 100644
diff --git a/sites/all/modules/contrib/panels/panels/plugins/display_renderers/standard.inc b/sites/all/modules/contrib/panels/panels/plugins/display_renderers/standard.inc
old mode 100755
new mode 100644
diff --git a/sites/all/modules/contrib/panels/panels/plugins/export_ui/panels_layouts.inc b/sites/all/modules/contrib/panels/panels/plugins/export_ui/panels_layouts.inc
old mode 100755
new mode 100644
diff --git a/sites/all/modules/contrib/panels/panels/plugins/export_ui/panels_layouts_ui.class.php b/sites/all/modules/contrib/panels/panels/plugins/export_ui/panels_layouts_ui.class.php
old mode 100755
new mode 100644
index 256cdaa9..ecf3b7bd
--- a/sites/all/modules/contrib/panels/panels/plugins/export_ui/panels_layouts_ui.class.php
+++ b/sites/all/modules/contrib/panels/panels/plugins/export_ui/panels_layouts_ui.class.php
@@ -125,9 +125,19 @@ class panels_layouts_ui extends ctools_export_ui {
function edit_form_submit(&$form, &$form_state) {
parent::edit_form_submit($form, $form_state);
+
+ // While we short circuited the main submit hook, we need to keep this one.
+ panels_edit_display_settings_form_submit($form, $form_state);
$form_state['item']->settings = $form_state['display']->layout_settings;
}
+ function edit_form_validate(&$form, &$form_state) {
+ parent::edit_form_validate($form, $form_state);
+
+ // While we short circuited the main validate hook, we need to keep this one.
+ panels_edit_display_settings_form_validate($form, $form_state);
+ }
+
function list_form(&$form, &$form_state) {
ctools_include('plugins', 'panels');
$this->builders = panels_get_layout_builders();
diff --git a/sites/all/modules/contrib/panels/panels/plugins/layouts/flexible/flexible-admin.css b/sites/all/modules/contrib/panels/panels/plugins/layouts/flexible/flexible-admin.css
old mode 100755
new mode 100644
diff --git a/sites/all/modules/contrib/panels/panels/plugins/layouts/flexible/flexible-admin.js b/sites/all/modules/contrib/panels/panels/plugins/layouts/flexible/flexible-admin.js
old mode 100755
new mode 100644
index 8dd3117b..2cddd42d
--- a/sites/all/modules/contrib/panels/panels/plugins/layouts/flexible/flexible-admin.js
+++ b/sites/all/modules/contrib/panels/panels/plugins/layouts/flexible/flexible-admin.js
@@ -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')
@@ -176,6 +176,10 @@ Drupal.flexible.splitter = function($splitter) {
function splitterMove(event) {
var diff = splitter.startX - event.pageX;
var moved = 0;
+
+ if (event.keyCode == 37) diff = 10;
+ if (event.keyCode == 39) diff = -10;
+
// Bah, javascript has no logical xor operator
if ((splitter.left_unit && !splitter.right_unit) ||
(!splitter.left_unit && splitter.right_unit)) {
@@ -286,13 +290,16 @@ 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;
};
+ function splitterKeyPress(event) {
+ splitterStart(event);
+ splitterMove(event);
+ splitterEnd(event);
+ };
+
function splitterEnd(event) {
if (splitter.left_unit) {
splitter.left_box.remove();
@@ -357,7 +364,8 @@ Drupal.flexible.splitter = function($splitter) {
splitter.right = $(splitter.right_class);
$splitter
- .bind("mousedown", splitterStart);
+ .bind("mousedown", splitterStart)
+ .bind("keydown", splitterKeyPress);
};
diff --git a/sites/all/modules/contrib/panels/panels/plugins/layouts/flexible/flexible.css b/sites/all/modules/contrib/panels/panels/plugins/layouts/flexible/flexible.css
old mode 100755
new mode 100644
diff --git a/sites/all/modules/contrib/panels/panels/plugins/layouts/flexible/flexible.inc b/sites/all/modules/contrib/panels/panels/plugins/layouts/flexible/flexible.inc
old mode 100755
new mode 100644
index 8f11bba7..4cdb216b
--- a/sites/all/modules/contrib/panels/panels/plugins/layouts/flexible/flexible.inc
+++ b/sites/all/modules/contrib/panels/panels/plugins/layouts/flexible/flexible.inc
@@ -255,7 +255,11 @@ function panels_flexible_panels($display, $settings, $layout) {
$items = array();
panels_flexible_convert_settings($settings, $layout);
foreach ($settings['items'] as $id => $item) {
- if ($item['type'] == 'region') {
+ // Remove garbage values.
+ if (!isset($item['type'])) {
+ unset($items[$id]);
+ }
+ else if ($item['type'] == 'region') {
$items[$id] = $item['title'];
}
}
@@ -467,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] : " ";
- $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] : " ";
+ }
+ 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;
}
@@ -593,7 +608,8 @@ function panels_flexible_render_splitter($renderer, $left_id, $right_id) {
$right_class = $left_class;
}
- $output = '';
+ $output = '';
// Name the left object
$output .= '';
@@ -742,47 +758,47 @@ function panels_flexible_render_css_group($renderer, $list, $owner_id, $type, $i
$css = array();
// Start off with some generic CSS to properly pad regions
- $css['.' . $renderer->item_class['region']] = array(
+ $css[$owner_id . ' .' . $renderer->item_class['region']] = array(
'padding' => '0',
);
- $css['.' . $renderer->item_class['region'] . '-inside'] = array(
+ $css[$owner_id . ' .' . $renderer->item_class['region'] . '-inside'] = array(
'padding-right' => $renderer->region_separation,
'padding-left' => $renderer->region_separation,
);
- $css['.' . $renderer->item_class['region'] . '-inside-first'] = array(
+ $css[$owner_id . ' .' . $renderer->item_class['region'] . '-inside-first'] = array(
'padding-left' => '0',
);
- $css['.' . $renderer->item_class['region'] . '-inside-last'] = array(
+ $css[$owner_id . ' .' . $renderer->item_class['region'] . '-inside-last'] = array(
'padding-right' => '0',
);
- $css['.' . $renderer->item_class['column']] = array(
+ $css[$owner_id . ' .' . $renderer->item_class['column']] = array(
'padding' => '0',
);
- $css['.' . $renderer->item_class['column'] . '-inside'] = array(
+ $css[$owner_id . ' .' . $renderer->item_class['column'] . '-inside'] = array(
'padding-right' => $renderer->column_separation,
'padding-left' => $renderer->column_separation,
);
- $css['.' . $renderer->item_class['column'] . '-inside-first'] = array(
+ $css[$owner_id . ' .' . $renderer->item_class['column'] . '-inside-first'] = array(
'padding-left' => '0',
);
- $css['.' . $renderer->item_class['column'] . '-inside-last'] = array(
+ $css[$owner_id . ' .' . $renderer->item_class['column'] . '-inside-last'] = array(
'padding-right' => '0',
);
// And properly pad rows too
- $css['.' . $renderer->item_class['row']] = array(
+ $css[$owner_id . ' .' . $renderer->item_class['row']] = array(
'padding' => '0 0 ' . $renderer->row_separation . ' 0',
'margin' => '0',
);
- $css['.' . $renderer->item_class['row'] . '-last'] = array(
+ $css[$owner_id . ' .' . $renderer->item_class['row'] . '-last'] = array(
'padding-bottom' => '0',
);
@@ -1181,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'),
@@ -1218,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'];
}
@@ -1481,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'),
@@ -1511,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']));
diff --git a/sites/all/modules/contrib/panels/panels/plugins/layouts/flexible/flexible.png b/sites/all/modules/contrib/panels/panels/plugins/layouts/flexible/flexible.png
old mode 100755
new mode 100644
diff --git a/sites/all/modules/contrib/panels/panels/plugins/layouts/flexible/grippie-vertical.png b/sites/all/modules/contrib/panels/panels/plugins/layouts/flexible/grippie-vertical.png
old mode 100755
new mode 100644
diff --git a/sites/all/modules/contrib/panels/panels/plugins/layouts/onecol/onecol.css b/sites/all/modules/contrib/panels/panels/plugins/layouts/onecol/onecol.css
old mode 100755
new mode 100644
diff --git a/sites/all/modules/contrib/panels/panels/plugins/layouts/onecol/onecol.inc b/sites/all/modules/contrib/panels/panels/plugins/layouts/onecol/onecol.inc
old mode 100755
new mode 100644
diff --git a/sites/all/modules/contrib/panels/panels/plugins/layouts/onecol/onecol.png b/sites/all/modules/contrib/panels/panels/plugins/layouts/onecol/onecol.png
old mode 100755
new mode 100644
diff --git a/sites/all/modules/contrib/panels/panels/plugins/layouts/onecol/panels-onecol.tpl.php b/sites/all/modules/contrib/panels/panels/plugins/layouts/onecol/panels-onecol.tpl.php
old mode 100755
new mode 100644
diff --git a/sites/all/modules/contrib/panels/panels/plugins/layouts/threecol_25_50_25/panels-threecol-25-50-25.tpl.php b/sites/all/modules/contrib/panels/panels/plugins/layouts/threecol_25_50_25/panels-threecol-25-50-25.tpl.php
old mode 100755
new mode 100644
diff --git a/sites/all/modules/contrib/panels/panels/plugins/layouts/threecol_25_50_25/threecol_25_50_25.css b/sites/all/modules/contrib/panels/panels/plugins/layouts/threecol_25_50_25/threecol_25_50_25.css
old mode 100755
new mode 100644
diff --git a/sites/all/modules/contrib/panels/panels/plugins/layouts/threecol_25_50_25/threecol_25_50_25.inc b/sites/all/modules/contrib/panels/panels/plugins/layouts/threecol_25_50_25/threecol_25_50_25.inc
old mode 100755
new mode 100644
diff --git a/sites/all/modules/contrib/panels/panels/plugins/layouts/threecol_25_50_25/threecol_25_50_25.png b/sites/all/modules/contrib/panels/panels/plugins/layouts/threecol_25_50_25/threecol_25_50_25.png
old mode 100755
new mode 100644
diff --git a/sites/all/modules/contrib/panels/panels/plugins/layouts/threecol_25_50_25_stacked/panels-threecol-25-50-25-stacked.tpl.php b/sites/all/modules/contrib/panels/panels/plugins/layouts/threecol_25_50_25_stacked/panels-threecol-25-50-25-stacked.tpl.php
old mode 100755
new mode 100644
diff --git a/sites/all/modules/contrib/panels/panels/plugins/layouts/threecol_25_50_25_stacked/threecol_25_50_25_stacked.css b/sites/all/modules/contrib/panels/panels/plugins/layouts/threecol_25_50_25_stacked/threecol_25_50_25_stacked.css
old mode 100755
new mode 100644
index 1aa00dad..c24dabf9
--- a/sites/all/modules/contrib/panels/panels/plugins/layouts/threecol_25_50_25_stacked/threecol_25_50_25_stacked.css
+++ b/sites/all/modules/contrib/panels/panels/plugins/layouts/threecol_25_50_25_stacked/threecol_25_50_25_stacked.css
@@ -18,7 +18,7 @@
width: 25%;
}
-.panel-3col-stacked .panel-col .inside {
+.panel-3col-stacked .panel-col-first .inside {
margin: 0 .5em 1em .5em;
}
diff --git a/sites/all/modules/contrib/panels/panels/plugins/layouts/threecol_25_50_25_stacked/threecol_25_50_25_stacked.inc b/sites/all/modules/contrib/panels/panels/plugins/layouts/threecol_25_50_25_stacked/threecol_25_50_25_stacked.inc
old mode 100755
new mode 100644
diff --git a/sites/all/modules/contrib/panels/panels/plugins/layouts/threecol_25_50_25_stacked/threecol_25_50_25_stacked.png b/sites/all/modules/contrib/panels/panels/plugins/layouts/threecol_25_50_25_stacked/threecol_25_50_25_stacked.png
old mode 100755
new mode 100644
diff --git a/sites/all/modules/contrib/panels/panels/plugins/layouts/threecol_33_34_33/panels-threecol-33-34-33.tpl.php b/sites/all/modules/contrib/panels/panels/plugins/layouts/threecol_33_34_33/panels-threecol-33-34-33.tpl.php
old mode 100755
new mode 100644
diff --git a/sites/all/modules/contrib/panels/panels/plugins/layouts/threecol_33_34_33/threecol_33_34_33.css b/sites/all/modules/contrib/panels/panels/plugins/layouts/threecol_33_34_33/threecol_33_34_33.css
old mode 100755
new mode 100644
diff --git a/sites/all/modules/contrib/panels/panels/plugins/layouts/threecol_33_34_33/threecol_33_34_33.inc b/sites/all/modules/contrib/panels/panels/plugins/layouts/threecol_33_34_33/threecol_33_34_33.inc
old mode 100755
new mode 100644
diff --git a/sites/all/modules/contrib/panels/panels/plugins/layouts/threecol_33_34_33/threecol_33_34_33.png b/sites/all/modules/contrib/panels/panels/plugins/layouts/threecol_33_34_33/threecol_33_34_33.png
old mode 100755
new mode 100644
diff --git a/sites/all/modules/contrib/panels/panels/plugins/layouts/threecol_33_34_33_stacked/panels-threecol-33-34-33-stacked.tpl.php b/sites/all/modules/contrib/panels/panels/plugins/layouts/threecol_33_34_33_stacked/panels-threecol-33-34-33-stacked.tpl.php
old mode 100755
new mode 100644
diff --git a/sites/all/modules/contrib/panels/panels/plugins/layouts/threecol_33_34_33_stacked/threecol_33_34_33_stacked.css b/sites/all/modules/contrib/panels/panels/plugins/layouts/threecol_33_34_33_stacked/threecol_33_34_33_stacked.css
old mode 100755
new mode 100644
diff --git a/sites/all/modules/contrib/panels/panels/plugins/layouts/threecol_33_34_33_stacked/threecol_33_34_33_stacked.inc b/sites/all/modules/contrib/panels/panels/plugins/layouts/threecol_33_34_33_stacked/threecol_33_34_33_stacked.inc
old mode 100755
new mode 100644
diff --git a/sites/all/modules/contrib/panels/panels/plugins/layouts/threecol_33_34_33_stacked/threecol_33_34_33_stacked.png b/sites/all/modules/contrib/panels/panels/plugins/layouts/threecol_33_34_33_stacked/threecol_33_34_33_stacked.png
old mode 100755
new mode 100644
diff --git a/sites/all/modules/contrib/panels/panels/plugins/layouts/twocol/panels-twocol.tpl.php b/sites/all/modules/contrib/panels/panels/plugins/layouts/twocol/panels-twocol.tpl.php
old mode 100755
new mode 100644
diff --git a/sites/all/modules/contrib/panels/panels/plugins/layouts/twocol/twocol.css b/sites/all/modules/contrib/panels/panels/plugins/layouts/twocol/twocol.css
old mode 100755
new mode 100644
diff --git a/sites/all/modules/contrib/panels/panels/plugins/layouts/twocol/twocol.inc b/sites/all/modules/contrib/panels/panels/plugins/layouts/twocol/twocol.inc
old mode 100755
new mode 100644
diff --git a/sites/all/modules/contrib/panels/panels/plugins/layouts/twocol/twocol.png b/sites/all/modules/contrib/panels/panels/plugins/layouts/twocol/twocol.png
old mode 100755
new mode 100644
diff --git a/sites/all/modules/contrib/panels/panels/plugins/layouts/twocol_bricks/panels-twocol-bricks.tpl.php b/sites/all/modules/contrib/panels/panels/plugins/layouts/twocol_bricks/panels-twocol-bricks.tpl.php
old mode 100755
new mode 100644
diff --git a/sites/all/modules/contrib/panels/panels/plugins/layouts/twocol_bricks/twocol_bricks.css b/sites/all/modules/contrib/panels/panels/plugins/layouts/twocol_bricks/twocol_bricks.css
old mode 100755
new mode 100644
diff --git a/sites/all/modules/contrib/panels/panels/plugins/layouts/twocol_bricks/twocol_bricks.inc b/sites/all/modules/contrib/panels/panels/plugins/layouts/twocol_bricks/twocol_bricks.inc
old mode 100755
new mode 100644
diff --git a/sites/all/modules/contrib/panels/panels/plugins/layouts/twocol_bricks/twocol_bricks.png b/sites/all/modules/contrib/panels/panels/plugins/layouts/twocol_bricks/twocol_bricks.png
old mode 100755
new mode 100644
diff --git a/sites/all/modules/contrib/panels/panels/plugins/layouts/twocol_stacked/panels-twocol-stacked.tpl.php b/sites/all/modules/contrib/panels/panels/plugins/layouts/twocol_stacked/panels-twocol-stacked.tpl.php
old mode 100755
new mode 100644
diff --git a/sites/all/modules/contrib/panels/panels/plugins/layouts/twocol_stacked/twocol_stacked.css b/sites/all/modules/contrib/panels/panels/plugins/layouts/twocol_stacked/twocol_stacked.css
old mode 100755
new mode 100644
diff --git a/sites/all/modules/contrib/panels/panels/plugins/layouts/twocol_stacked/twocol_stacked.inc b/sites/all/modules/contrib/panels/panels/plugins/layouts/twocol_stacked/twocol_stacked.inc
old mode 100755
new mode 100644
diff --git a/sites/all/modules/contrib/panels/panels/plugins/layouts/twocol_stacked/twocol_stacked.png b/sites/all/modules/contrib/panels/panels/plugins/layouts/twocol_stacked/twocol_stacked.png
old mode 100755
new mode 100644
diff --git a/sites/all/modules/contrib/panels/panels/plugins/page_wizards/landing_page.inc b/sites/all/modules/contrib/panels/panels/plugins/page_wizards/landing_page.inc
old mode 100755
new mode 100644
index d9428dad..030318f1
--- a/sites/all/modules/contrib/panels/panels/plugins/page_wizards/landing_page.inc
+++ b/sites/all/modules/contrib/panels/panels/plugins/page_wizards/landing_page.inc
@@ -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');
diff --git a/sites/all/modules/contrib/panels/panels/plugins/panels_storage/page_manager.inc b/sites/all/modules/contrib/panels/panels/plugins/panels_storage/page_manager.inc
new file mode 100644
index 00000000..afb3aec2
--- /dev/null
+++ b/sites/all/modules/contrib/panels/panels/plugins/panels_storage/page_manager.inc
@@ -0,0 +1,19 @@
+ '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);
+}
diff --git a/sites/all/modules/contrib/panels/panels/plugins/style_bases/pane/pane_plain_box/icon.png b/sites/all/modules/contrib/panels/panels/plugins/style_bases/pane/pane_plain_box/icon.png
old mode 100755
new mode 100644
diff --git a/sites/all/modules/contrib/panels/panels/plugins/style_bases/pane/pane_plain_box/pane-plain-box.css b/sites/all/modules/contrib/panels/panels/plugins/style_bases/pane/pane_plain_box/pane-plain-box.css
old mode 100755
new mode 100644
diff --git a/sites/all/modules/contrib/panels/panels/plugins/style_bases/pane/pane_plain_box/pane-plain-box.tpl.php b/sites/all/modules/contrib/panels/panels/plugins/style_bases/pane/pane_plain_box/pane-plain-box.tpl.php
old mode 100755
new mode 100644
diff --git a/sites/all/modules/contrib/panels/panels/plugins/style_bases/pane/pane_plain_box/pane_plain_box.inc b/sites/all/modules/contrib/panels/panels/plugins/style_bases/pane/pane_plain_box/pane_plain_box.inc
old mode 100755
new mode 100644
diff --git a/sites/all/modules/contrib/panels/panels/plugins/style_bases/pane/pane_rounded_shadow/box-color.png b/sites/all/modules/contrib/panels/panels/plugins/style_bases/pane/pane_rounded_shadow/box-color.png
old mode 100755
new mode 100644
diff --git a/sites/all/modules/contrib/panels/panels/plugins/style_bases/pane/pane_rounded_shadow/box-shadow.png b/sites/all/modules/contrib/panels/panels/plugins/style_bases/pane/pane_rounded_shadow/box-shadow.png
old mode 100755
new mode 100644
diff --git a/sites/all/modules/contrib/panels/panels/plugins/style_bases/pane/pane_rounded_shadow/icon.png b/sites/all/modules/contrib/panels/panels/plugins/style_bases/pane/pane_rounded_shadow/icon.png
old mode 100755
new mode 100644
diff --git a/sites/all/modules/contrib/panels/panels/plugins/style_bases/pane/pane_rounded_shadow/pane-rounded-shadow.css b/sites/all/modules/contrib/panels/panels/plugins/style_bases/pane/pane_rounded_shadow/pane-rounded-shadow.css
old mode 100755
new mode 100644
diff --git a/sites/all/modules/contrib/panels/panels/plugins/style_bases/pane/pane_rounded_shadow/pane-rounded-shadow.tpl.php b/sites/all/modules/contrib/panels/panels/plugins/style_bases/pane/pane_rounded_shadow/pane-rounded-shadow.tpl.php
old mode 100755
new mode 100644
diff --git a/sites/all/modules/contrib/panels/panels/plugins/style_bases/pane/pane_rounded_shadow/pane_rounded_shadow.inc b/sites/all/modules/contrib/panels/panels/plugins/style_bases/pane/pane_rounded_shadow/pane_rounded_shadow.inc
old mode 100755
new mode 100644
diff --git a/sites/all/modules/contrib/panels/panels/plugins/style_bases/region/region_plain_box/icon.png b/sites/all/modules/contrib/panels/panels/plugins/style_bases/region/region_plain_box/icon.png
old mode 100755
new mode 100644
diff --git a/sites/all/modules/contrib/panels/panels/plugins/style_bases/region/region_plain_box/region-plain-box.css b/sites/all/modules/contrib/panels/panels/plugins/style_bases/region/region_plain_box/region-plain-box.css
old mode 100755
new mode 100644
diff --git a/sites/all/modules/contrib/panels/panels/plugins/style_bases/region/region_plain_box/region-plain-box.tpl.php b/sites/all/modules/contrib/panels/panels/plugins/style_bases/region/region_plain_box/region-plain-box.tpl.php
old mode 100755
new mode 100644
diff --git a/sites/all/modules/contrib/panels/panels/plugins/style_bases/region/region_plain_box/region_plain_box.inc b/sites/all/modules/contrib/panels/panels/plugins/style_bases/region/region_plain_box/region_plain_box.inc
old mode 100755
new mode 100644
diff --git a/sites/all/modules/contrib/panels/panels/plugins/style_bases/region/region_rounded_shadow/box-color.png b/sites/all/modules/contrib/panels/panels/plugins/style_bases/region/region_rounded_shadow/box-color.png
old mode 100755
new mode 100644
diff --git a/sites/all/modules/contrib/panels/panels/plugins/style_bases/region/region_rounded_shadow/box-shadow.png b/sites/all/modules/contrib/panels/panels/plugins/style_bases/region/region_rounded_shadow/box-shadow.png
old mode 100755
new mode 100644
diff --git a/sites/all/modules/contrib/panels/panels/plugins/style_bases/region/region_rounded_shadow/icon.png b/sites/all/modules/contrib/panels/panels/plugins/style_bases/region/region_rounded_shadow/icon.png
old mode 100755
new mode 100644
diff --git a/sites/all/modules/contrib/panels/panels/plugins/style_bases/region/region_rounded_shadow/region-rounded-shadow.css b/sites/all/modules/contrib/panels/panels/plugins/style_bases/region/region_rounded_shadow/region-rounded-shadow.css
old mode 100755
new mode 100644
diff --git a/sites/all/modules/contrib/panels/panels/plugins/style_bases/region/region_rounded_shadow/region-rounded-shadow.tpl.php b/sites/all/modules/contrib/panels/panels/plugins/style_bases/region/region_rounded_shadow/region-rounded-shadow.tpl.php
old mode 100755
new mode 100644
diff --git a/sites/all/modules/contrib/panels/panels/plugins/style_bases/region/region_rounded_shadow/region_rounded_shadow.inc b/sites/all/modules/contrib/panels/panels/plugins/style_bases/region/region_rounded_shadow/region_rounded_shadow.inc
old mode 100755
new mode 100644
diff --git a/sites/all/modules/contrib/panels/panels/plugins/styles/block.inc b/sites/all/modules/contrib/panels/panels/plugins/styles/block.inc
old mode 100755
new mode 100644
index 4614ee49..58815a32
--- a/sites/all/modules/contrib/panels/panels/plugins/styles/block.inc
+++ b/sites/all/modules/contrib/panels/panels/plugins/styles/block.inc
@@ -31,6 +31,9 @@ function theme_panels_block_style_render_pane($vars) {
if (!empty($block->title)) {
$block->subject = $block->title;
}
+ if (!isset($block->subject)) {
+ $block->subject = '';
+ }
$block->region = $pane->panel;
if (!isset($block->module)) {
diff --git a/sites/all/modules/contrib/panels/panels/plugins/styles/corners/corner-bits.png b/sites/all/modules/contrib/panels/panels/plugins/styles/corners/corner-bits.png
old mode 100755
new mode 100644
diff --git a/sites/all/modules/contrib/panels/panels/plugins/styles/corners/panels-rounded-corners-box.tpl.php b/sites/all/modules/contrib/panels/panels/plugins/styles/corners/panels-rounded-corners-box.tpl.php
old mode 100755
new mode 100644
diff --git a/sites/all/modules/contrib/panels/panels/plugins/styles/corners/rounded_corners.inc b/sites/all/modules/contrib/panels/panels/plugins/styles/corners/rounded_corners.inc
old mode 100755
new mode 100644
index dd511704..a1d800b7
--- a/sites/all/modules/contrib/panels/panels/plugins/styles/corners/rounded_corners.inc
+++ b/sites/all/modules/contrib/panels/panels/plugins/styles/corners/rounded_corners.inc
@@ -125,7 +125,7 @@ function panels_rounded_corners_css($display) {
$filename = ctools_css_store($css_id, _panels_rounded_corners_css($idstr), FALSE);
}
- drupal_add_css($filename, 'module', 'all', FALSE);
+ drupal_add_css($filename, array('preprocess' => TRUE));
}
/**
diff --git a/sites/all/modules/contrib/panels/panels/plugins/styles/corners/shadow-b.png b/sites/all/modules/contrib/panels/panels/plugins/styles/corners/shadow-b.png
old mode 100755
new mode 100644
diff --git a/sites/all/modules/contrib/panels/panels/plugins/styles/corners/shadow-l.png b/sites/all/modules/contrib/panels/panels/plugins/styles/corners/shadow-l.png
old mode 100755
new mode 100644
diff --git a/sites/all/modules/contrib/panels/panels/plugins/styles/corners/shadow-r.png b/sites/all/modules/contrib/panels/panels/plugins/styles/corners/shadow-r.png
old mode 100755
new mode 100644
diff --git a/sites/all/modules/contrib/panels/panels/plugins/styles/corners/shadow-t.png b/sites/all/modules/contrib/panels/panels/plugins/styles/corners/shadow-t.png
old mode 100755
new mode 100644
diff --git a/sites/all/modules/contrib/panels/panels/plugins/styles/default.inc b/sites/all/modules/contrib/panels/panels/plugins/styles/default.inc
old mode 100755
new mode 100644
diff --git a/sites/all/modules/contrib/panels/panels/plugins/styles/list.inc b/sites/all/modules/contrib/panels/panels/plugins/styles/list.inc
old mode 100755
new mode 100644
diff --git a/sites/all/modules/contrib/panels/panels/plugins/styles/naked.inc b/sites/all/modules/contrib/panels/panels/plugins/styles/naked.inc
old mode 100755
new mode 100644
diff --git a/sites/all/modules/contrib/panels/panels/plugins/styles/stylizer.inc b/sites/all/modules/contrib/panels/panels/plugins/styles/stylizer.inc
old mode 100755
new mode 100644
index 6b7ae253..f892024b
--- a/sites/all/modules/contrib/panels/panels/plugins/styles/stylizer.inc
+++ b/sites/all/modules/contrib/panels/panels/plugins/styles/stylizer.inc
@@ -194,10 +194,14 @@ function panels_stylizer_stylizer_style_settings_form($style_settings, $display,
* Allow on-the-fly creation of styles in panes.
*/
function panels_stylizer_pane_add_style(&$renderer, $plugin, &$conf, $type, $pid, $step = NULL) {
- if (!user_access('administer panels styles')) {
+ if (!user_access("administer panels $type styles")) {
return;
}
+ // Reset the $_POST['ajax_html_ids'] values to preserve
+ // proper IDs on form elements when auto-submit is used.
+ $_POST['ajax_html_ids'] = array();
+
ctools_include('stylizer');
$js = FALSE;
@@ -271,7 +275,7 @@ function panels_stylizer_pane_add_style(&$renderer, $plugin, &$conf, $type, $pid
* preconfigured style.
*/
function panels_stylizer_edit_pane_style_form(&$form, &$form_state) {
- if (!user_access('administer panels styles') || !module_exists('stylizer')) {
+ if (!user_access('administer panels pane styles') || !module_exists('stylizer')) {
return;
}
ctools_include('dependent');
@@ -318,7 +322,7 @@ function panels_stylizer_edit_pane_style_form(&$form, &$form_state) {
* Validate to see if we need to check the preconfigured values.
*/
function panels_stylizer_edit_pane_style_form_validate(&$form, &$form_state) {
- if (!user_access('administer panels styles')) {
+ if (!user_access('administer panels pane styles')) {
return;
}
@@ -352,7 +356,7 @@ function panels_stylizer_edit_pane_style_form_validate(&$form, &$form_state) {
* Store the preconfigured values.
*/
function panels_stylizer_edit_pane_style_form_submit(&$form, &$form_state) {
- if (!user_access('administer panels styles')) {
+ if (!user_access('administer panels pane styles')) {
return;
}
diff --git a/sites/all/modules/contrib/panels/panels/plugins/task_handlers/panel_context.inc b/sites/all/modules/contrib/panels/panels/plugins/task_handlers/panel_context.inc
old mode 100755
new mode 100644
index 86512f66..daa98ac7
--- a/sites/all/modules/contrib/panels/panels/plugins/task_handlers/panel_context.inc
+++ b/sites/all/modules/contrib/panels/panels/plugins/task_handlers/panel_context.inc
@@ -184,7 +184,9 @@ $plugin = array(
'default conf' => array(
'title' => t('Panel'),
'no_blocks' => FALSE,
- 'pipeline' => 'standard',
+ 'pipeline' => variable_get('panels_renderer_default', 'standard'),
+ 'body_classes_to_remove' => '',
+ 'body_classes_to_add' => '',
'css_id' => '',
'css' => '',
'contexts' => array(),
@@ -217,23 +219,45 @@ function panels_panel_context_tab_operation($handler, $contexts, $args) {
* for the handler and pla
*/
function &panels_panel_context_get_display(&$handler) {
- if (isset($handler->conf['display'])) {
- return $handler->conf['display'];
- }
+ if (!isset($handler->conf['display'])) {
+ if (isset($handler->conf['did'])) {
+ $handler->conf['display'] = panels_load_display($handler->conf['did']);
+ }
- if (isset($handler->conf['did'])) {
- $handler->conf['display'] = panels_load_display($handler->conf['did']);
-
- // Check for a valid display. If no valid display can be loaded, something
- // is wrong and we'll create a new one.
- if (!empty($handler->conf['display'])) {
- return $handler->conf['display'];
+ // Check for again for a valid display. If no valid display could be loaded,
+ // something is wrong and we'll create a new one.
+ if (empty($handler->conf['display'])) {
+ $handler->conf['display'] = panels_new_display();
}
}
- $handler->conf['display'] = panels_new_display();
+ $display =& $handler->conf['display'];
+ $display->storage_type = 'page_manager';
+ $display->storage_id = !empty($handler->name) ? $handler->name : 'new';
- return $handler->conf['display'];
+ return $display;
+}
+
+/**
+ * Build the cache key so that the editor and IPE can properly find
+ * everything needed for this display.
+ */
+function panels_panel_context_cache_key($task_name, $handler_id, $args) {
+ $arguments = array();
+ foreach ($args as $arg) {
+ // Sadly things like panels everywhere actually use non-string arguments
+ // and they basically can't be represented here. Luckily, PE also does
+ // not use a system where this matters, so replace its args with a 0
+ // for a placeholder.
+ if (is_string($arg)) {
+ $arguments[] = $arg;
+ }
+ else {
+ $arguments[] = '0';
+ }
+ }
+ $cache_key = 'panel_context:' . $task_name . '::' . $handler_id . '::' . implode('\\', $arguments) . '::';
+ return $cache_key;
}
/**
@@ -262,10 +286,11 @@ 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 = 'panel_context:' . $task_name . ':' . $handler->name;
+ $display->cache_key = panels_panel_context_cache_key($task_name, $handler->name, $args);
// Check to see if there is any CSS.
if (!empty($handler->conf['css'])) {
@@ -273,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);
}
@@ -282,6 +309,35 @@ function panels_panel_context_render($handler, $base_contexts, $args, $test = TR
panels_get_current_page_display($display);
$renderer = panels_get_renderer($handler->conf['pipeline'], $display);
+ // If the IPE is enabled, but the user does not have access to edit
+ // load the standard renderer instead.
+
+ $parents = class_parents($renderer);
+ if (!empty($parents['panels_renderer_editor']) && !user_access('user page manager') && !user_access('use ipe with page manager')) {
+ $renderer = panels_get_renderer_handler('standard', $display);
+ }
+
+ // Remove and add body element classes
+ $panel_body_css = &drupal_static('panel_body_css');
+
+ 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'])) {
+ $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(
'content' => panels_render_display($display, $renderer),
@@ -315,8 +371,8 @@ function panels_panel_context_save(&$handler, $update) {
ctools_include('css');
ctools_css_clear('panel_context:' . $handler->name);
- if (isset($page->conf['temp_layout'])) {
- unset($page->conf['temp_layout']);
+ if (isset($handler->conf['temp_layout'])) {
+ unset($handler->conf['temp_layout']);
}
}
@@ -352,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;
}
@@ -617,6 +676,8 @@ function panels_panel_context_edit_move($form, &$form_state) {
$form_state['display'] = &panels_panel_context_get_display($form_state['handler']);
$form_state['layout'] = $form_state['handler']->conf['temp_layout'];
+ $form_state['cache_key'] = panels_panel_context_cache_key($form_state['task_name'], $form_state['handler_id'], array());
+
ctools_include('common', 'panels');
ctools_include('display-layout', 'panels');
ctools_include('plugins', 'panels');
@@ -652,7 +713,7 @@ function panels_panel_context_edit_content($form, &$form_state) {
ctools_include('context');
ctools_include('context-task-handler');
- $cache = panels_edit_cache_get('panel_context:' . $form_state['task_name'] . ':' . $form_state['handler_id']);
+ $cache = panels_edit_cache_get(panels_panel_context_cache_key($form_state['task_name'], $form_state['handler_id'], array()));
$form_state['renderer'] = panels_get_renderer_handler('editor', $cache->display);
$form_state['renderer']->cache = &$cache;
@@ -682,6 +743,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'];
@@ -714,6 +779,22 @@ function panels_panel_context_edit_settings($form, &$form_state) {
'#description' => t('Check this to have the page disable all regions displayed in the theme. Note that some themes support this setting better than others. If in doubt, try with stock themes to see.'),
);
+ $form['conf']['body_classes_to_remove'] = array(
+ '#type' => 'textfield',
+ '#size' => 128,
+ '#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. Keywords from context are allowed.'),
+ );
+
+ $form['conf']['body_classes_to_add'] = array(
+ '#type' => 'textfield',
+ '#size' => 128,
+ '#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. Keywords from context are allowed.'),
+ );
+
ctools_include('plugins', 'panels');
$pipelines = panels_get_renderer_pipelines();
@@ -751,13 +832,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'],
);
@@ -769,6 +850,8 @@ function panels_panel_context_edit_settings($form, &$form_state) {
*/
function panels_panel_context_edit_settings_submit(&$form, &$form_state) {
$form_state['handler']->conf['no_blocks'] = $form_state['values']['no_blocks'];
+ $form_state['handler']->conf['body_classes_to_remove'] = $form_state['values']['body_classes_to_remove'];
+ $form_state['handler']->conf['body_classes_to_add'] = $form_state['values']['body_classes_to_add'];
$form_state['handler']->conf['pipeline'] = $form_state['values']['pipeline'];
$form_state['handler']->conf['css_id'] = $form_state['values']['css_id'];
$form_state['handler']->conf['css'] = $form_state['values']['css'];
@@ -836,15 +919,28 @@ function panels_panel_context_get_addressable($task, $subtask_name, $handler, $a
$display->context = $contexts;
$display->args = $arguments;
$display->css_id = $handler->conf['css_id'];
- $display->cache_key = 'panel_context:' . $task->name . ':' . $handler->name;
+ $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;
}
}
}
diff --git a/sites/all/modules/contrib/panels/panels/plugins/views/panels.views.inc b/sites/all/modules/contrib/panels/panels/plugins/views/panels.views.inc
old mode 100755
new mode 100644
index a04502d9..2418da53
--- a/sites/all/modules/contrib/panels/panels/plugins/views/panels.views.inc
+++ b/sites/all/modules/contrib/panels/panels/plugins/views/panels.views.inc
@@ -13,6 +13,7 @@ function panels_views_plugins() {
'path' => drupal_get_path('module', 'panels') . '/plugins/views',
'theme' => 'views_view_fields',
'theme path' => drupal_get_path('module', 'views') . '/theme',
+ 'register theme' => FALSE,
'uses fields' => TRUE,
'uses options' => TRUE,
'type' => 'normal',
diff --git a/sites/all/modules/contrib/panels/panels/plugins/views/panels_views_plugin_row_fields.inc b/sites/all/modules/contrib/panels/panels/plugins/views/panels_views_plugin_row_fields.inc
old mode 100755
new mode 100644
index 814350e4..4a404abc
--- a/sites/all/modules/contrib/panels/panels/plugins/views/panels_views_plugin_row_fields.inc
+++ b/sites/all/modules/contrib/panels/panels/plugins/views/panels_views_plugin_row_fields.inc
@@ -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));
}
diff --git a/sites/all/modules/contrib/panels/panels/templates/panels-add-content-link.tpl.php b/sites/all/modules/contrib/panels/panels/templates/panels-add-content-link.tpl.php
new file mode 100644
index 00000000..149ac829
--- /dev/null
+++ b/sites/all/modules/contrib/panels/panels/templates/panels-add-content-link.tpl.php
@@ -0,0 +1,14 @@
+
+
diff --git a/sites/all/modules/contrib/panels/panels/templates/panels-add-content-modal.tpl.php b/sites/all/modules/contrib/panels/panels/templates/panels-add-content-modal.tpl.php
new file mode 100644
index 00000000..4c4dff8e
--- /dev/null
+++ b/sites/all/modules/contrib/panels/panels/templates/panels-add-content-modal.tpl.php
@@ -0,0 +1,44 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ $column): ?>
+
+
+
+
+
+
+
+
+
diff --git a/sites/all/modules/contrib/panels/panels/templates/panels-dashboard-block.tpl.php b/sites/all/modules/contrib/panels/panels/templates/panels-dashboard-block.tpl.php
old mode 100755
new mode 100644
diff --git a/sites/all/modules/contrib/panels/panels/templates/panels-dashboard-link.tpl.php b/sites/all/modules/contrib/panels/panels/templates/panels-dashboard-link.tpl.php
old mode 100755
new mode 100644
diff --git a/sites/all/modules/contrib/panels/panels/templates/panels-dashboard.tpl.php b/sites/all/modules/contrib/panels/panels/templates/panels-dashboard.tpl.php
old mode 100755
new mode 100644
index 75c9e4c6..109deabc
--- a/sites/all/modules/contrib/panels/panels/templates/panels-dashboard.tpl.php
+++ b/sites/all/modules/contrib/panels/panels/templates/panels-dashboard.tpl.php
@@ -1,11 +1,11 @@
-
-
+
+
-
+
diff --git a/sites/all/modules/contrib/panels/panels/templates/panels-pane.tpl.php b/sites/all/modules/contrib/panels/panels/templates/panels-pane.tpl.php
old mode 100755
new mode 100644
index 93dd113d..0aa01021
--- a/sites/all/modules/contrib/panels/panels/templates/panels-pane.tpl.php
+++ b/sites/all/modules/contrib/panels/panels/templates/panels-pane.tpl.php
@@ -20,14 +20,16 @@
->
+ >
- >
+ <>
+
+ >
diff --git a/sites/all/modules/contrib/panels/panels/tests/PanelsEntityViewWebTestCase.test b/sites/all/modules/contrib/panels/panels/tests/PanelsEntityViewWebTestCase.test
new file mode 100644
index 00000000..03116d74
--- /dev/null
+++ b/sites/all/modules/contrib/panels/panels/tests/PanelsEntityViewWebTestCase.test
@@ -0,0 +1,103 @@
+checkPermissions(array(), TRUE);
+ cache_clear_all();
+
+ // Create the admin user.
+ $this->adminUser = $this->drupalCreateUser($permissions);
+ }
+
+ /**
+ * Ensure that the {ENTITY}_view toggle works correctly.
+ */
+ function testToggle() {
+ // Log in as the admin user.
+ $this->drupalLogin($this->adminUser);
+
+ // Load the Panels dashboard.
+ $this->drupalGet('admin/structure/panels');
+ $this->assertResponse(200, 'Loaded the main Panels admin page.');
+
+ // Confirm that the Node View task handler is disabled.
+ $this->assertText(t($this->view_label));
+ $this->assertLinkByHref(url('admin/structure/pages/edit/' . $this->view_name, array('absolute' => FALSE)));
+ $xpath = $this->xpath("//tr[contains(@class,:tr)]/td/div/div/ul/li[contains(@class,:li)]/a", array(':tr' => 'page-task-' . $this->view_name, ':li' => 'first'));
+ $this->assertEqual($xpath[0][0], t('Enable'));
+
+ // Set the Node View handler to "off".
+ variable_set('page_manager_' . $this->view_name . '_disabled', TRUE);
+
+ // Load the Panels dashboard again.
+ $this->drupalGet('admin/structure/panels');
+ $this->assertResponse(200, 'Loaded the main Panels admin page.');
+
+ // Confirm that the Node View task handler is still disabled.
+ $this->assertText(t($this->view_label));
+ $this->assertNoLinkByHref(url('admin/structure/pages/nojs/disable/' . $this->view_name, array('absolute' => FALSE)));
+ $xpath = $this->xpath("//tr[contains(@class,:tr)]/td/div/div/ul/li[contains(@class,:li)]/a", array(':tr' => 'page-task-' . $this->view_name, ':li' => 'first'));
+ $this->assertEqual($xpath[0][0], t('Enable'));
+
+ // Set the Node View handler to "on".
+ variable_set('page_manager_' . $this->view_name . '_disabled', FALSE);
+
+ // Load the Panels dashboard again.
+ $this->drupalGet('admin/structure/panels');
+ $this->assertResponse(200, 'Loaded the main Panels admin page.');
+
+ // Confirm that the Node View task handler is now enabled.
+ $this->assertLinkByHref(url('admin/structure/pages/nojs/disable/' . $this->view_name, array('absolute' => FALSE)));
+ $xpath = $this->xpath("//tr[contains(@class,:tr)]/td/div/div/ul/li[contains(@class,:li)]/a", array(':tr' => 'page-task-' . $this->view_name, ':li' => 'last'));
+ $this->assertEqual($xpath[0][0], t('Disable'));
+ }
+
+}
diff --git a/sites/all/modules/contrib/panels/panels/tests/PanelsNodeViewWebTestCase.test b/sites/all/modules/contrib/panels/panels/tests/PanelsNodeViewWebTestCase.test
new file mode 100644
index 00000000..5bf8f4b9
--- /dev/null
+++ b/sites/all/modules/contrib/panels/panels/tests/PanelsNodeViewWebTestCase.test
@@ -0,0 +1,31 @@
+ 'Panels node_view tests',
+ 'description' => 'Test the standard node_view task handler.',
+ 'group' => 'Panels',
+ );
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected $view_name = 'node_view';
+
+ /**
+ * {@inheritdoc}
+ */
+ protected $view_label = 'Node template';
+
+}
diff --git a/sites/all/modules/contrib/panels/panels/tests/PanelsTermViewWebTestCase.test b/sites/all/modules/contrib/panels/panels/tests/PanelsTermViewWebTestCase.test
new file mode 100644
index 00000000..2af6a6e5
--- /dev/null
+++ b/sites/all/modules/contrib/panels/panels/tests/PanelsTermViewWebTestCase.test
@@ -0,0 +1,31 @@
+ 'Panels term_view tests',
+ 'description' => 'Test the standard term_view task handler.',
+ 'group' => 'Panels',
+ );
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected $view_name = 'term_view';
+
+ /**
+ * {@inheritdoc}
+ */
+ protected $view_label = 'Taxonomy term template';
+
+}
diff --git a/sites/all/modules/contrib/panels/panels/tests/PanelsUserViewWebTestCase.test b/sites/all/modules/contrib/panels/panels/tests/PanelsUserViewWebTestCase.test
new file mode 100644
index 00000000..98afd7a0
--- /dev/null
+++ b/sites/all/modules/contrib/panels/panels/tests/PanelsUserViewWebTestCase.test
@@ -0,0 +1,31 @@
+ 'Panels user_view tests',
+ 'description' => 'Test the standard user_view task handler.',
+ 'group' => 'Panels',
+ );
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected $view_name = 'user_view';
+
+ /**
+ * {@inheritdoc}
+ */
+ protected $view_label = 'Users';
+
+}