diff --git a/fieldable_panels_panes.module b/fieldable_panels_panes.module
index cc8c072..bd9bca2 100644
--- a/fieldable_panels_panes.module
+++ b/fieldable_panels_panes.module
@@ -410,6 +410,14 @@ function fieldable_panels_panes_menu() {
'type' => MENU_LOCAL_ACTION,
) + $base;
+ $items['admin/ajax/fieldable-panels-panes/clone/%'] = array(
+ 'page callback' => 'fieldable_panels_pane_clone_ajax_endpoint',
+ 'page arguments' => array(4),
+ 'theme callback' => 'ajax_base_page_theme',
+ 'delivery callback' => 'ajax_deliver',
+ 'type' => MENU_CALLBACK,
+ ) + $base;
+
return $items;
}
@@ -1373,3 +1381,146 @@ function fieldable_panels_panes_entity_uri_callback($entity) {
'options' => array(),
);
}
+
+/**
+ * Implements hook_panelizer_tab_links_alter().
+ */
+function fieldable_panels_panes_panels_ipe_pane_links_alter(&$links, $context) {
+ if ($context['pane']->type == 'fieldable_panels_pane' && count(fieldable_panles_panes_pane_shares($context['pane']->pid)) > 1) {
+ ctools_add_css('fieldable_panels_panes_ipe', 'fieldable_panels_panes');
+ $links['fieldable_panels_pane_clone'] = array(
+ 'title' => '' . t('Clone') . '',
+ 'href' => url('admin/ajax/fieldable-panels-panes/clone/' . $context['pane']->pid . '/ipe', array('absolute' => TRUE)),
+ 'html' => TRUE,
+ 'attributes' => array(
+ 'class' => 'use-ajax',
+ 'id' => "pane-clone-panel-pane-{$context['pane']->pid}",
+ 'title' => t('Clone'),
+ ),
+ );
+ }
+}
+
+/**
+ * Implements hook_get_pane_links_alter().
+ */
+function fieldable_panels_panes_get_pane_links_alter(&$links, $pane, $content_type) {
+ if ($pane->type == 'fieldable_panels_pane' && count(fieldable_panles_panes_pane_shares($pane->pid)) > 1) {
+ $links['top']['fieldable_panels_pane_clone'] = array(
+ 'title' => t('Clone'),
+ 'href' => url('admin/ajax/fieldable-panels-panes/clone/' . $pane->pid . '/panels', array('absolute' => TRUE)),
+ 'attributes' => array('class' => array('use-ajax')),
+ );
+ }
+}
+
+/**
+ * Get all panes that reference same fieldable panel pane
+ *
+ * @param $pid
+ *
+ * @return array
+ */
+function fieldable_panles_panes_pane_shares($pid) {
+ $cache = &drupal_static(__FUNCTION__);
+ if (!isset($cache[$pid])) {
+ $query = db_select('panels_pane', 'p');
+ $query->fields('ps', array('pid'));
+ $query->innerJoin('panels_pane', 'ps', 'p.subtype = ps.subtype');
+ $query->condition('p.pid', $pid);
+ $query->countQuery();
+ $cache[$pid] = $query->execute()->fetchCol();
+ }
+ return $cache[$pid];
+}
+
+/**
+ * Fix cloned fieldable panel pane that reference to single entity
+ *
+ * @param $pid
+ *
+ * @return bool
+ *
+ * @throws \Exception
+ * @throws \InvalidMergeQueryException
+ */
+function _fieldable_panels_panes_clone($pid) {
+
+ $query = db_select('panels_pane', 'pp');
+ $query->fields('pp');
+ $query->condition('pid', $pid);
+ $query->range(0, 1);
+ $result = $query->execute();
+
+ $pane = $result->fetch();
+ if (!$pane) {
+ return FALSE;
+ }
+
+ // Copy from _fieldable_panels_panes_load_entity().
+ list($type, $id) = explode(':', $pane->subtype);
+ if ($type == 'uuid' && module_exists('uuid')) {
+ $ids = entity_get_id_by_uuid('fieldable_panels_pane', array($id));
+ if ($content = entity_load('fieldable_panels_pane', $ids)) {
+ $content = reset($content);
+ }
+ }
+ elseif ($type == 'vid') {
+ $fpid = db_query('SELECT fpid FROM {fieldable_panels_panes_revision} WHERE vid = :vid', array(':vid' => $id))->fetchField();
+ $content = fieldable_panels_panes_load($fpid, $id);
+ }
+ else {
+ $content = fieldable_panels_panes_load($id);
+ }
+
+ if (!$content) {
+ return FALSE;
+ }
+ // Copy of entity_ui_clone_entity() from entity module.
+
+ // Clone the entity and make sure it will get saved as a new entity.
+ $new_entity = clone $content;
+
+ $entity_info = entity_get_info('fieldable_panels_pane');
+ $new_entity->{$entity_info['entity keys']['id']} = FALSE;
+ if (!empty($entity_info['entity keys']['name'])) {
+ $new_entity->{$entity_info['entity keys']['name']} = FALSE;
+ }
+ $new_entity->is_new = TRUE;
+
+ // Make sure the status of a cloned exportable is custom.
+ if (!empty($entity_info['exportable'])) {
+ $status_key = isset($entity_info['entity keys']['status']) ? $entity_info['entity keys']['status'] : 'status';
+ $new_entity->$status_key = ENTITY_CUSTOM;
+ }
+
+ if ($type == 'uuid' && module_exists('uuid')) {
+ $new_entity->vuuid = NULL;
+ $new_entity->uuid = NULL;
+ }
+ if (!empty($new_entity->vid)) {
+ $new_entity->vid = NULL;
+ }
+
+ $new_entity = fieldable_panels_panes_save($new_entity);
+ if (!$new_entity) {
+ return FALSE;
+ }
+
+ if (module_exists('uuid') && isset($new_entity->uuid)) {
+ $new_pane_subtype = 'uuid:' . $new_entity->uuid;
+ }
+ else {
+ $new_pane_subtype = 'fpid:' . $new_entity->fpid;
+ }
+
+ db_merge('panels_pane')
+ ->key(array('pid' => $pid))
+ ->fields(array(
+ 'subtype' => $new_pane_subtype,
+ ))
+ ->execute();
+
+ return TRUE;
+}
+
diff --git a/includes/admin.inc b/includes/admin.inc
index fa62511..753dae7 100644
--- a/includes/admin.inc
+++ b/includes/admin.inc
@@ -190,3 +190,39 @@ function fieldable_panels_panes_entity_make_current_page($entity) {
drupal_set_message(t('The revision has been made current.'));
drupal_goto("admin/structure/fieldable-panels-panes/view/$entity->fpid");
}
+
+/**
+ * AJAX endpoint for panelizer and panels pane editing menues
+ *
+ * @param $pid
+ * @param $editing_mode
+ *
+ * @return array
+ */
+function fieldable_panels_pane_clone_ajax_endpoint($pid, $editing_mode = 'panels') {
+
+ $commands = array();
+
+ if (is_numeric($pid) && _fieldable_panels_panes_clone($pid)) {
+ $cloned_pane_label_markup = '' . t('(Cloned pane)') . '';
+ if ($editing_mode == 'ipe') {
+ $commands[] = ajax_command_changed("#panels-ipe-paneid-{$pid}", "div.panels-ipe-dragbar span.panels-ipe-dragbar-admin-title");
+ $commands[] = ajax_command_remove("#panels-ipe-paneid-{$pid} li.fieldable_panels_pane_clone");
+ $commands[] = ajax_command_before("#panels-ipe-paneid-{$pid} div.panels-ipe-dragbar span.panels-ipe-dragbar-admin-title", $cloned_pane_label_markup);
+ }
+ else {
+ $commands[] = ajax_command_changed("#panel-pane-{$pid}", "div.grab-title span.text");
+ $commands[] = ajax_command_remove("#panel-pane-{$pid} li.fieldable_panels_pane_clone");
+ $commands[] = ajax_command_before("#panel-pane-{$pid} div.grab-title span.text", $cloned_pane_label_markup);
+ }
+ }
+ else {
+ $commands[] = ajax_command_alert(t('Problem while clonning pane'));
+ }
+
+ return array(
+ '#type' => 'ajax',
+ '#commands' => $commands,
+ );
+
+}