Projet

Général

Profil

Paste
Télécharger (64,8 ko) Statistiques
| Branche: | Révision:

root / drupal7 / sites / all / modules / panelizer / panelizer.module @ 136a805a

1
<?php
2
/**
3
 * @file
4
 * The Panelizer module attaches panels to entities, providing default panels
5
 * and allowing each panel to be configured independently by privileged users.
6
 */
7

    
8
define('PANELIZER_VERSION', '3.0');
9

    
10
// -----------------------------------------------------------------------
11
// Drupal core hooks
12

    
13
/**
14
 * Implements hook_help().
15
 */
16
function panelizer_help($path, $arg) {
17
  if ($path == 'admin/structure/panelizer') {
18
    return '<p>' . t('Other than "Full page override" or "Default" (when applicable), only view modes enabled through the Custom Display Settings section of the <em>Manage Display</em> settings for that entity or bundle will be available for use.') . '</p>';
19
  }
20
}
21

    
22
/**
23
 * Implements hook_hook_info().
24
 */
25
function panelizer_hook_info() {
26
  $hooks = array(
27
    'panelizer_defaults_override_alter',
28
    'panelizer_entity_plugin_process_alter',
29
    'panelizer_operations_alter',
30
  );
31

    
32
  return array_fill_keys($hooks, array('group' => 'panelizer'));
33
}
34

    
35
/**
36
 * Implements hook_permission().
37
 */
38
function panelizer_permission() {
39
  $items = array(
40
    'administer panelizer' => array(
41
      'title' => t('administer panelizer'),
42
      'description' => t('Fully administer panelizer and all panelizer settings.'),
43
    ),
44
  );
45

    
46
  // Delegate.
47
  foreach (panelizer_get_plugins_with_hook('permission') as $handler) {
48
    $handler->hook_permission($items);
49
  }
50

    
51
  return $items;
52
}
53

    
54
/**
55
 * Implements hook_og_permission().
56
 */
57
function panelizer_og_permission() {
58
  $items = array();
59

    
60
  // Delegate.
61
  foreach (panelizer_get_plugins_with_hook('permission') as $handler) {
62
    if ($handler->entity_type == 'node') {
63
      $handler->hook_permission($items);
64
    }
65
  }
66

    
67
  $final = array(
68
    'administer panelizer og_group defaults' => array(
69
      'title' => t('Group: Administer Panelizer default panels, allowed content and settings.'),
70
      'description' => t('Users with this permission can fully administer panelizer for this entity bundle.'),
71
    ),
72
    'administer panelizer og_group overview' => array(
73
      'title' => t('Group: Administer Panelizer overview.'),
74
      'description' => t('Allow access to the panelizer overview page for the entity type/bundle. Note: This permission will be required for panelizer tabs to appear on an entity.'),
75
    ),
76
  );
77

    
78
  foreach (panelizer_operations() as $path => $operation) {
79
    $final["administer panelizer og_group $path"] = array(
80
      'title' => t('Group: Administer Panelizer @operation', array(
81
        '@operation' => $operation['link title'],
82
      )),
83
    );
84
  }
85

    
86
  foreach ($items as $key => $item) {
87
    // Get node bundle.
88
    $words = explode(' ', $key);
89
    $bundle = $words[3];
90
    if (og_is_group_content_type('node', $bundle)) {
91
      $final[$key] = $item;
92
    }
93
  }
94

    
95
  return $final;
96
}
97

    
98
/**
99
 * Implements hook_theme().
100
 */
101
function panelizer_theme() {
102
  $items = array();
103

    
104
  $items['panelizer_settings_page_table'] = array(
105
    'render element' => 'element',
106
    'file' => 'includes/admin.inc',
107
  );
108

    
109
  $items['panelizer_view_mode'] = array(
110
    'render element' => 'element',
111
    'template' => 'panelizer-view-mode',
112
    'path' => drupal_get_path('module', 'panelizer') . '/templates',
113
  );
114

    
115
  // Delegate.
116
  foreach (panelizer_get_plugins_with_hook('theme') as $handler) {
117
    $handler->hook_theme($items);
118
  }
119

    
120
  return $items;
121
}
122

    
123
/**
124
 * Implements hook_menu().
125
 */
126
function panelizer_menu() {
127
  $items = array();
128

    
129
  // Delegate admin menu stuff to admin.inc.
130
  ctools_include('admin', 'panelizer');
131
  panelizer_admin_hook_menu($items);
132

    
133
  // Delegate.
134
  foreach (panelizer_get_plugins_with_hook('menu') as $handler) {
135
    $handler->hook_menu($items);
136
  }
137

    
138
  return $items;
139
}
140

    
141
/**
142
 * Implements hook_menu_alter().
143
 */
144
function panelizer_menu_alter(&$items) {
145
  // Delegate.
146
  foreach (panelizer_get_plugins_with_hook('menu_alter') as $handler) {
147
    $handler->hook_menu_alter($items);
148
  }
149
}
150

    
151
/**
152
 * Implements hook_admin_paths().
153
 */
154
function panelizer_admin_paths() {
155
  $items = array();
156

    
157
  // Delegate.
158
  foreach (panelizer_get_plugins_with_hook('admin_paths') as $handler) {
159
    $handler->hook_admin_paths($items);
160
  }
161

    
162
  return $items;
163
}
164

    
165
/**
166
 * Implements hook_panels_ipe_access().
167
 */
168
function panelizer_panels_ipe_access($display) {
169
  // We only care about Panels displays from panelizer.
170
  if (isset($display->context['panelizer'])) {
171
    // The type array contains 3 elements, where the first is the full context
172
    // type (ie. 'entity:ENTITY_TYPE'), and the remaining two are the parts
173
    // seperated by ':', so 'entity' and the entity type name.
174
    $entity_type = $display->context['panelizer']->type[2];
175
    if ($handler = panelizer_entity_plugin_get_handler($entity_type)) {
176
      // Only allow access to use the IPE if the user has 'update' access to
177
      // the underlying entity.
178
      $entity = $display->context['panelizer']->data;
179
      return $handler->entity_access('update', $entity);
180
    }
181
  }
182
}
183

    
184
/**
185
 * Implements hook_form_FORM_ID_alter().
186
 *
187
 * Check whether a given view mode is panelized. Set an error message if there
188
 * are un-hidden fields because they won't be printed anyway.
189
 */
190
function panelizer_form_field_ui_display_overview_form_alter(&$form, &$form_state, $form_id) {
191
  if (!empty($form['#entity_type']) && !empty($form['#bundle']) && !empty($form['#view_mode'])) {
192
    module_load_install('panelizer');
193
    if (panelizer_view_mode_extra_field_displays($form['#entity_type'], $form['#bundle'], $form['#view_mode'])) {
194
      $message = t("This view mode is being controlled via Panelizer. For performance reasons, it is recommended to move all fields to 'hidden'. Fields not marked as hidden will be prepared for output but will not actually output, thus needlessly increasing render and page load time.");
195
      drupal_set_message($message, 'error', FALSE);
196
    }
197
  }
198
}
199

    
200
/**
201
 * Implements hook_form_alter().
202
 */
203
function panelizer_form_alter(&$form, &$form_state, $form_id) {
204
  // Delegate.
205
  foreach (panelizer_get_plugins_with_hook('form_alter') as $handler) {
206
    $handler->hook_form_alter($form, $form_state, $form_id);
207

    
208
    // Support default content and layout settings.
209
    foreach ($handler->plugin['bundles'] as $bundle_name => $bundle) {
210
      if ($form_id == 'panels_common_settings' && $form_state['build_info']['args'][0] == 'panelizer_' . $handler->entity_type . ':' . $bundle_name) {
211

    
212
        // Provide settings for the default content and layout options.
213
        $form['default_settings'] = array(
214
          '#type' => 'fieldset',
215
          '#title' => t('Default settings'),
216
          '#group' => 'additional_settings',
217
          '#weight' => -20,
218
        );
219
        $form['default_settings']['default_content_settings'] = array(
220
          '#title' => t('Use the same allowed content as standard Panels pages?'),
221
          '#type' => 'checkbox',
222
          '#default_value' => variable_get($form_state['build_info']['args'][0] . '_allowed_types_default', FALSE),
223
        );
224
        $form['default_settings']['default_layout_settings'] = array(
225
          '#title' => t('Use the same allowed  layouts as standard Panels pages?'),
226
          '#type' => 'checkbox',
227
          '#default_value' => variable_get($form_state['build_info']['args'][0] . '_allowed_layouts_default', FALSE),
228
        );
229

    
230
        // Disable the layout options when the default layout setting is enabled
231
        if (!empty($form['layout_selection']['layouts']) && variable_get($form_state['build_info']['args'][0] . '_allowed_layouts_default', FALSE)) {
232
          $form['layout_selection']['layouts']['#disabled'] = TRUE;
233
        }
234

    
235
        // Disable the content options when the default content setting is
236
        // enabled.
237
        if (variable_get($form_state['build_info']['args'][0] . '_allowed_types_default', FALSE)) {
238
          $content_types = ctools_content_get_all_types();
239
          $content_types['other'] = array('title' => t('Other'), 'weight' => 10);
240
          foreach ($content_types as $content_type => $content_type_value) {
241
            if (!empty($form['content_types'][$content_type]['options'])) {
242
              $form['content_types'][$content_type]['options']['#disabled'] = TRUE;
243
            }
244
          }
245
          $form['common']['panels_common_default']['#disabled'] = TRUE;
246
        }
247

    
248
        $form['#submit'][] = 'panelizer_panels_default_settings_submit';
249
      }
250
    }
251
  }
252
}
253

    
254
/**
255
 * Custom submission handler for setting default content and layout settings.
256
 */
257
function panelizer_panels_default_settings_submit($form, &$form_state) {
258
  variable_set($form_state['values']['module_name'] . '_allowed_types_default', $form_state['values']['default_content_settings']);
259
  variable_set($form_state['values']['module_name'] . '_allowed_layouts_default', $form_state['values']['default_layout_settings']);
260
}
261

    
262
/**
263
 * Implements hook_process_page().
264
 */
265
function panelizer_process_page(&$variables) {
266
  // Delegate.
267
  // Target the theme layer to ensure we can manipulate the overview table.
268
  foreach (panelizer_get_plugins_with_hook('page_alter') as $handler) {
269
    $handler->hook_page_alter($variables['page']);
270
  }
271
}
272

    
273
/**
274
 * Implements hook_entity_load().
275
 */
276
function panelizer_entity_load(&$entities, $entity_type) {
277
  // Delegate to the handler.
278
  if ($handler = panelizer_entity_plugin_get_handler($entity_type)) {
279
    $handler->hook_entity_load($entities);
280
  }
281
}
282

    
283
/**
284
 * Implements hook_entity_update().
285
 */
286
function panelizer_entity_update($entity, $entity_type) {
287
  // Delegate to the handler.
288
  if ($handler = panelizer_entity_plugin_get_handler($entity_type)) {
289
    $handler->hook_entity_update($entity);
290
  }
291
}
292

    
293
/**
294
 * Implements hook_entity_insert().
295
 */
296
function panelizer_entity_insert($entity, $entity_type) {
297
  // Delegate to the handler.
298
  if ($handler = panelizer_entity_plugin_get_handler($entity_type)) {
299
    $handler->hook_entity_insert($entity);
300
  }
301
}
302

    
303
/**
304
 * Implements hook_entity_delete().
305
 */
306
function panelizer_entity_delete($entity, $entity_type) {
307
  // Delegate to the handler.
308
  if ($handler = panelizer_entity_plugin_get_handler($entity_type)) {
309
    $handler->hook_entity_delete($entity);
310
  }
311
}
312

    
313
/**
314
 * Implements hook_field_attach_delete_revision().
315
 */
316
function panelizer_field_attach_delete_revision($entity_type, $entity) {
317
  // Delegate to the handler.
318
  if ($handler = panelizer_entity_plugin_get_handler($entity_type)) {
319
    $handler->hook_field_attach_delete_revision($entity);
320
  }
321
}
322

    
323
function panelizer_field_attach_form($entity_type, $entity, &$form, &$form_state, $langcode) {
324
  // Delegate to the handler.
325
  if ($handler = panelizer_entity_plugin_get_handler($entity_type)) {
326
    $handler->hook_field_attach_form($entity, $form, $form_state, $langcode);
327
  }
328
}
329

    
330
function panelizer_field_attach_submit($entity_type, $entity, &$form, &$form_state) {
331
  // Delegate to the handler.
332
  if ($handler = panelizer_entity_plugin_get_handler($entity_type)) {
333
    $handler->hook_field_attach_submit($entity, $form, $form_state);
334
  }
335
}
336

    
337
/**
338
 * Implements hook_entity_view_alter().
339
 */
340
function panelizer_entity_view_alter(&$build, $entity_type) {
341
  static $recursion_prevention = array();
342
  // Prepare variables.
343
  $handler = panelizer_entity_plugin_get_handler($entity_type);
344
  if (!$handler) {
345
    return;
346
  }
347

    
348
  $entity = $handler->get_entity_view_entity($build);
349

    
350
  // Safety check in case the entity can't be loaded.
351
  if (!$entity) {
352
    return;
353
  }
354

    
355
  list($entity_id, $revision_id, $bundle) = entity_extract_ids($entity_type, $entity);
356

    
357
  // If the requested view mode does not exist, check if a substitute is
358
  // assigned, otherwise rendering will fall back to 'default' and we should
359
  // check that one instead.
360
  $view_mode = $handler->get_view_mode($build['#view_mode'], $bundle);
361

    
362
  // Make sure the bundle + view mode is actually panelized!
363
  if (!$handler->is_panelized($bundle . '.' . $view_mode)) {
364
    return;
365
  }
366

    
367
  // Also verify that the configuration exists. This may happen if a display is
368
  // improperly configured.
369
  if (empty($entity->panelizer[$view_mode])) {
370
    return;
371
  }
372

    
373
  if (!empty($recursion_prevention[$entity_type][$entity_id][$view_mode])) {
374
    return;
375
  }
376

    
377
  $recursion_prevention[$entity_type][$entity_id][$view_mode] = TRUE;
378

    
379
  if ($info = $handler->render_entity($entity, $view_mode)) {
380
    // Change theming function and add the content on the $build array.
381
    $build['#theme'] = 'panelizer_view_mode';
382
    $build['#panelizer'] = $entity->panelizer[$view_mode];
383
    $build['#panelizer_content'] = $info;
384
    $build['#panelizer_handler'] = $handler;
385
    $build['#panelizer_entity'] = $entity;
386
    $build['#panelizer_bundle'] = $bundle;
387
    $build['#panelizer_entity_id'] = $entity_id;
388
  }
389
  $recursion_prevention[$entity_type][$entity_id][$view_mode] = FALSE;
390
}
391

    
392
/**
393
 * Implements hook_node_update_index().
394
 */
395
function panelizer_node_update_index($node) {
396
  // Populate search index for nodes managed via Panelizer if 'search_index'
397
  // view mode is configured to do so.
398
  if (
399
    ($handler = panelizer_entity_plugin_get_handler('node'))
400
    && ($view_mode = $handler->get_view_mode('search_index', $node->type))
401
    && $handler->is_panelized($node->type . '.' . $view_mode)
402
    && !empty($node->panelizer[$view_mode])
403
    && ($info = $handler->render_entity($node, $view_mode))
404
  ) {
405
    $build['#view_mode'] = $view_mode;
406
    $build['#theme'] = 'panelizer_view_mode';
407
    $build['#panelizer'] = $node->panelizer[$view_mode];
408
    $build['#panelizer_content'] = $info;
409
    $build['#panelizer_handler'] = $handler;
410
    $build['#panelizer_entity'] = $node;
411
    $build['#panelizer_bundle'] = $node->type;
412
    $build['#panelizer_entity_id'] = $node->nid;
413
    return drupal_render($build);
414
  }
415
}
416

    
417
/**
418
 * Implements hook_node_search_result().
419
 */
420
function panelizer_node_search_result($node) {
421
  // Populate search result highlighting input for nodes managed via Panelizer
422
  // if 'search_result' view mode is configured to do so.
423
  if (
424
    ($handler = panelizer_entity_plugin_get_handler('node'))
425
    && ($view_mode = $handler->get_view_mode('search_result', $node->type))
426
    && $handler->is_panelized($node->type . '.' . $view_mode)
427
    && !empty($node->panelizer[$view_mode])
428
    && ($info = $handler->render_entity($node, $view_mode))
429
  ) {
430
    $build['#view_mode'] = $view_mode;
431
    $build['#theme'] = 'panelizer_view_mode';
432
    $build['#panelizer'] = $node->panelizer[$view_mode];
433
    $build['#panelizer_content'] = $info;
434
    $build['#panelizer_handler'] = $handler;
435
    $build['#panelizer_entity'] = $node;
436
    $build['#panelizer_bundle'] = $node->type;
437
    $build['#panelizer_entity_id'] = $node->nid;
438
    $node->rendered .= drupal_render($build);
439
  }
440
}
441

    
442
// -----------------------------------------------------------------------
443
// Panels and CTools hooks
444

    
445
/**
446
 * Implements hook_ctools_plugin_type().
447
 */
448
function panelizer_ctools_plugin_type() {
449
  $items['entity'] = array(
450
    'cache' => FALSE,
451
    'process' => array(
452
      'function' => 'panelizer_entity_plugin_process',
453
    ),
454
    'classes' => array('handler'),
455
  );
456

    
457
  return $items;
458
}
459

    
460
/**
461
 * Implements hook_ctools_plugin_directory().
462
 */
463
function panelizer_ctools_plugin_directory($module, $plugin) {
464
  if (in_array($module, array('panelizer', 'ctools', 'page_manager'))) {
465
    return 'plugins/' . $plugin;
466
  }
467
  if ($module == 'panels' && $plugin == 'panels_storage') {
468
    return 'plugins/' . $plugin;
469
  }
470
}
471

    
472
/**
473
 * Implements hook_ctools_plugin_api().
474
 */
475
function panelizer_ctools_plugin_api($module, $api) {
476
  if (($module == 'page_manager' && $api == 'pages_default') || $module == 'panelizer') {
477
    return array(
478
      'version' => 1,
479
      'path' => drupal_get_path('module', 'panelizer') . '/includes',
480
    );
481
  }
482
}
483

    
484
/**
485
 * Implements hook_features_api().
486
 */
487
function panelizer_features_api() {
488
  $api = array();
489
  if (function_exists('_ctools_features_get_info') && defined('FEATURES_ALTER_TYPE_NONE')) {
490
    $api['panelizer_defaults'] = _ctools_features_get_info('panelizer_defaults');
491
    // CTools calls our hook_panelizer_defaults_alter so prevent Features from
492
    // calling it too. FEATURES_ALTER_TYPE_INLINE means we are handling alter
493
    // hooks ourselves here.
494
    $api['panelizer_defaults']['alter_type'] = FEATURES_ALTER_TYPE_INLINE;
495
    // Provide a separate alter hook for features_override.
496
    $api['panelizer_defaults']['alter_hook'] = 'panelizer_defaults_override';
497
  }
498

    
499
  return $api;
500
}
501

    
502
/**
503
 * Implementation of hook_views_api().
504
 */
505
function panelizer_views_api() {
506
  return array(
507
    'api' => 2.0,
508
    'path' => drupal_get_path('module', 'panelizer') . '/plugins/views',
509
  );
510
}
511

    
512
/**
513
 * Implements hook_panelizer_defaults_alter().
514
 */
515
function panelizer_panelizer_defaults_alter(&$items) {
516
  // Delegate.
517
  foreach (panelizer_get_plugins_with_hook('panelizer_defaults') as $handler) {
518
    $handler->hook_panelizer_defaults($items);
519
  }
520

    
521
  // Allow features_overrides to alter the config.
522
  drupal_alter('panelizer_defaults_override', $items);
523
}
524

    
525
/**
526
 * Implements hook_default_page_manager_handlers().
527
 */
528
function panelizer_default_page_manager_handlers() {
529
  $items = array();
530
  // Delegate.
531
  foreach (panelizer_get_plugins_with_hook('default_page_manager_handlers') as $handler) {
532
    $handler->hook_default_page_manager_handlers($items);
533
  }
534

    
535
  return $items;
536
}
537

    
538
/**
539
 * Implement CTools access form caching callback: get.
540
 */
541
function panelizer_ctools_access_get($argument) {
542
  list($entity_type, $bundle, $name) = explode(':', $argument);
543
  $handler = panelizer_entity_plugin_get_handler($entity_type);
544
  $panelizer = $handler->get_default_panelizer_object($bundle, $name);
545

    
546
  if (empty($panelizer)) {
547
    return;
548
  }
549

    
550
  if (!$handler->access_default_panelizer_object($panelizer)) {
551
    return;
552
  }
553

    
554
  // First, see if there's a cache.
555
  ctools_include('object-cache');
556
  $access = ctools_object_cache_get('panelizer_access', $argument);
557
  if (!$access) {
558
    $access = $panelizer->access;
559
  }
560

    
561
  $context = $handler->get_contexts($panelizer);
562

    
563
  return array($access, $context);
564
}
565

    
566
/**
567
 * Implement CTools access form caching callback: set.
568
 */
569
function panelizer_ctools_access_set($argument, $access) {
570
  list($entity_type, $bundle, $name) = explode(':', $argument);
571
  $handler = panelizer_entity_plugin_get_handler($entity_type);
572
  $panelizer = $handler->get_default_panelizer_object($bundle, $name);
573

    
574
  if (empty($panelizer)) {
575
    return;
576
  }
577

    
578
  if (!$handler->access_default_panelizer_object($panelizer)) {
579
    return;
580
  }
581

    
582
  ctools_include('object-cache');
583
  ctools_object_cache_set('panelizer_access', $argument, $access);
584
}
585

    
586
/**
587
 * Implement CTools access form caching callback: get.
588
 */
589
function panelizer_ctools_access_clear($argument) {
590
  list($entity_type, $bundle, $name) = explode(':', $argument);
591
  $handler = panelizer_entity_plugin_get_handler($entity_type);
592
  $panelizer = $handler->get_default_panelizer_object($bundle, $name);
593

    
594
  if (empty($panelizer)) {
595
    return;
596
  }
597

    
598
  if (!$handler->access_default_panelizer_object($panelizer)) {
599
    return;
600
  }
601

    
602
  ctools_include('object-cache');
603
  ctools_object_cache_clear('panelizer', $argument);
604
}
605

    
606
// -----------------------------------------------------------------------
607
// CTools entity plugin support code.
608

    
609
/**
610
 * CTools process callback for an entity plugin.
611
 *
612
 * This adds configuration data to the plugin so that we know what bundles it is
613
 * enabled for.
614
 */
615
function panelizer_entity_plugin_process(&$plugin, $info) {
616
  $entity_type = $plugin['name'];
617
  $entity_info = entity_get_info($entity_type);
618
  $plugin['bundles'] = array();
619
  if ($entity_info) {
620
    foreach ($entity_info['bundles'] as $bundle => $label) {
621
      if ($settings = variable_get('panelizer_defaults_' . $entity_type . '_' . $bundle, array())) {
622
        // Translate from settings that existed prior to view mode support.
623
        if (empty($settings['view modes'])) {
624
          $old_settings = $settings;
625
          $settings = array('view modes' => array());
626
          if (empty($plugin['uses page manager'])) {
627
            $settings['view modes']['default'] = $old_settings;
628
          }
629
          else {
630
            $settings['view modes']['page_manager'] = $old_settings;
631
          }
632
          $settings['status'] = $old_settings['status'];
633
        }
634
        $plugin['bundles'][$bundle] = $settings;
635

    
636
        // Build the custom settings of the view modes for this bundle.
637
        $view_mode_settings = field_view_mode_settings($entity_type, $bundle);
638
        foreach ($entity_info['view modes'] as $view_mode_name => $view_mode_info) {
639
          $plugin['view mode status'][$bundle][$view_mode_name] = !empty($view_mode_settings[$view_mode_name]['custom_settings']);
640
        }
641
      }
642
    }
643

    
644
    // Add our fake view modes.
645
    $plugin['view modes'] = array(
646
      'page_manager' => array(
647
        'label' => t('Full page override'),
648
      ),
649
      'default' => array(
650
        'label' => t('Default'),
651
      ),
652
    );
653

    
654
    if (!empty($entity_info['view modes'])) {
655
      foreach ($entity_info['view modes'] as $view_mode => $view_mode_info) {
656
        $plugin['view modes'][$view_mode] = $view_mode_info;
657
      }
658
    }
659

    
660
    // It seems silly to unset this after but the logic is cleaner to read.
661
    if (empty($plugin['uses page manager'])) {
662
      unset($plugin['view modes']['page_manager']);
663
    }
664
  }
665

    
666
  drupal_alter('panelizer_entity_plugin_process', $plugin, $info);
667
}
668

    
669
/**
670
 * Fetch a single entity plugin.
671
 */
672
function panelizer_get_entity_plugin($entity_type) {
673
  ctools_include('plugins');
674
  return ctools_get_plugins('panelizer', 'entity', $entity_type);
675
}
676

    
677
/**
678
 * Fetch all entity plugin.
679
 */
680
function panelizer_get_entity_plugins() {
681
  ctools_include('plugins');
682
  return ctools_get_plugins('panelizer', 'entity');
683
}
684

    
685
/**
686
 * Get the class to handle custom code for a given entity type plugin.
687
 *
688
 * If a plugin does not define a class at all, then the default class.
689
 *
690
 * @return
691
 *   Either the instantiated handler or FALSE if one could not be had.
692
 */
693
function panelizer_entity_plugin_get_handler($plugin) {
694
  // The default plugin handler is abstract and cannot be loaded.
695
  if ($plugin == 'default') {
696
    return;
697
  }
698

    
699
  $cache = &drupal_static(__FUNCTION__, array());
700

    
701
  // If a string was passed, turn it into a plugin.
702
  if (is_string($plugin)) {
703
    $plugin = panelizer_get_entity_plugin($plugin);
704
    if (!$plugin) {
705
      return FALSE;
706
    }
707
  }
708

    
709
  // Get the class name from the 'handler' property if we have not already
710
  // cached a handler.
711
  if (empty($cache[$plugin['name']]) && ($class = ctools_plugin_get_class($plugin, 'handler'))) {
712
    // @todo is there a good reason to use ->init instead of __construct?
713
    $cache[$plugin['name']] = new $class();
714
    $cache[$plugin['name']]->init($plugin);
715
  }
716
  return !empty($cache[$plugin['name']]) ? $cache[$plugin['name']] : FALSE;
717
}
718

    
719
/**
720
 * Load handler to get a plugin as a menu callback.
721
 */
722
function panelizer_handler_load($entity_type) {
723
  return panelizer_entity_plugin_get_handler($entity_type);
724
}
725

    
726
/**
727
 * Fetch handler objects for all plugins that implement the named hook.
728
 *
729
 * These plugins must set $plugin['hooks'][$hook] = TRUE in order to be
730
 * instantiated.
731
 *
732
 * This is only called for system wide hooks such as hook_menu and
733
 * hook_menu_alter; entity specific hooks will always be called.
734
 */
735
function panelizer_get_plugins_with_hook($hook) {
736
  $objects = array();
737
  $plugins = panelizer_get_entity_plugins();
738
  foreach ($plugins as $entity_type => $plugin) {
739
    if (!empty($plugin['hooks'][$hook])) {
740
      if ($handler = panelizer_entity_plugin_get_handler($plugin)) {
741
        $objects[$entity_type] = $handler;
742
      }
743
    }
744
  }
745

    
746
  return $objects;
747
}
748

    
749
/**
750
 * Page callback for entity menu callbacks.
751
 *
752
 * This function is to be used as a menu callback for menu items that are to be
753
 * handled by a method on the handler object. It loads the object defined in the
754
 * plugin and hands it off to a method based upon the name of the operation in
755
 * use.
756
 *
757
 * For example, if the 'op' is 'revision' then the callback method will be
758
 * 'page_revisions', with all of the arguments *except* the $op and the plugin
759
 * name.
760
 */
761
function panelizer_entity_plugin_switcher_page($entity_type, $op) {
762
  $args = func_get_args();
763

    
764
  // Load the $plugin information.
765
  if ($handler = panelizer_entity_plugin_get_handler($entity_type)) {
766
    // Replace the first two arguments.
767
    $args[0] = !empty($_REQUEST['js']);
768
    $args[1] = $_POST;
769
    if (empty($args[3])) {
770
      $args[3] = 'page_manager';
771
    }
772
    $method = 'page_' . $op;
773
    if (method_exists($handler, $method)) {
774
      return call_user_func_array(array($handler, $method), $args);
775
    }
776
    // Check to see if this is an operation from panelizer_operations with a
777
    // callback instead.
778
    $operations = panelizer_operations();
779
    if (isset($operations[$op]) && isset($operations[$op]['entity callback']) && function_exists($operations[$op]['entity callback'])) {
780
      array_unshift($args, $handler);
781
      return call_user_func_array($operations[$op]['entity callback'], $args);
782
    }
783
  }
784
  else {
785
    return t('Configuration error. No handler found.');
786
  }
787
}
788

    
789
/**
790
 * Callback used for switching callbacks into the proper plugin.
791
 */
792
function panelizer_entity_plugin_callback_switcher($entity_type, $switcher_type, $op) {
793
  $args = func_get_args();
794
  if (count($args) < 3) {
795
    return FALSE;
796
  }
797
  $entity_type = array_shift($args);
798
  $switcher_type = array_shift($args);
799
  $op = array_shift($args);
800

    
801
  // Load the $plugin information.
802
  if ($handler = panelizer_entity_plugin_get_handler($entity_type)) {
803
    $method = $switcher_type . '_' . $op;
804
    if (method_exists($handler, $method)) {
805
      return call_user_func_array(array($handler, $method), $args);
806
    }
807
  }
808
  else {
809
    return FALSE;
810
  }
811
}
812

    
813
/**
814
 * Page callback to delegate to either the settings page or list page.
815
 */
816
function panelizer_default_list_or_settings_page($handler, $bundle, $name, $view_mode, $operation = 'list', $item = NULL) {
817
  if (is_string($handler)) {
818
    $handler = panelizer_entity_plugin_get_handler($handler);
819
  }
820

    
821
  // We need a version of $bundle with $view_mode but we need to retain one
822
  // without it so we can pass straight $bundle to the settings page.
823
  $test_bundle = $bundle;
824
  if ($view_mode) {
825
    $test_bundle .= '.' . $view_mode;
826
  }
827

    
828
  if ($handler->has_panel_choice($test_bundle)) {
829
    // Call through to the UI switcher for the list.
830
    ctools_include('export-ui');
831
    return panelizer_export_ui_switcher_page($handler, $test_bundle, 'panelizer_defaults', $operation, $item);
832
  }
833
  else {
834
    return panelizer_default_settings_page($handler, $bundle, $name, $view_mode);
835
  }
836
}
837

    
838
/**
839
 * Specialized version of ctools_export_ui_switcher_page().
840
 *
841
 * This one is designed to set our entity handler and bundle on the object so we
842
 * can refer to it later without having to override all of the entry points.
843
 */
844
function panelizer_export_ui_switcher_page($entity_handler, $bundle, $plugin_name, $op) {
845
  $args = func_get_args();
846

    
847
  // Remove the handler and the bundle.
848
  array_shift($args);
849
  array_shift($args);
850
  $js = !empty($_REQUEST['js']);
851

    
852
  // Break our bundle up as necessary.
853
  if (strpos($bundle, '.') !== FALSE) {
854
    list($bundle, $view_mode) = explode('.', $bundle);
855
  }
856
  else {
857
    $view_mode = 'page_manager';
858
  }
859

    
860
  // Load the $plugin information.
861
  ctools_include('export-ui');
862
  $plugin = ctools_get_export_ui($plugin_name);
863
  $handler = ctools_export_ui_get_handler($plugin);
864

    
865
  if ($handler) {
866
    if (is_string($entity_handler)) {
867
      $entity_handler = panelizer_entity_plugin_get_handler($entity_handler);
868
    }
869

    
870
    $handler->entity_handler = $entity_handler;
871
    $handler->entity_bundle = $bundle;
872
    $handler->entity_view_mode = $view_mode;
873

    
874
    if (empty($entity_handler->entity_admin_root) || substr($_GET['q'], 30) == 'admin/structure/panelizer') {
875
      $handler->plugin['menu']['menu prefix'] = 'admin/structure/panelizer' . $entity_handler->entity_type;
876
      $handler->plugin['menu']['menu item'] = $bundle;
877
    }
878
    else {
879
      $base_path = $entity_handler->entity_admin_root . '/panelizer/' . $view_mode;
880
      if (is_numeric($entity_handler->entity_admin_bundle)) {
881
        $bits = explode('/', $base_path);
882
        $bits[$entity_handler->entity_admin_bundle] = $bundle;
883
        $base_path = implode('/', $bits);
884
      }
885
      $handler->plugin['menu']['menu prefix'] = dirname($base_path);
886
      $handler->plugin['menu']['menu item'] = basename($base_path);
887
      foreach ($handler->plugin['menu']['items'] as $key => &$item) {
888
        $item['path'] = str_replace('list/', '', $item['path']);
889
      }
890
    }
891

    
892
    $path = $handler->plugin['menu']['menu prefix'] . '/' . $handler->plugin['menu']['menu item'];
893

    
894
    foreach ($handler->plugin['redirect'] as $key => $old_path) {
895
      if ($key == 'add') {
896
        $handler->plugin['redirect'][$key] = $path . '/%ctools_export_ui/settings';
897
      }
898
      else {
899
        $handler->plugin['redirect'][$key] = $path;
900
      }
901
    }
902

    
903
    $method = $op . '_page';
904
    if (method_exists($handler, $method)) {
905
      // Replace the first two arguments.
906
      $args[0] = $js;
907
      $args[1] = $_POST;
908
      return call_user_func_array(array($handler, $method), $args);
909
    }
910
  }
911
  else {
912
    return t('Configuration error. No handler found.');
913
  }
914
}
915

    
916
// ---------------------------------------------------------------------------
917
// Menu callbacks
918

    
919
/**
920
 * Title callback to properly set the tile when editing panelizer defaults.
921
 */
922
function panelizer_default_title_callback($handler, $bundle) {
923
  if (is_string($handler)) {
924
    $handler = panelizer_entity_plugin_get_handler($handler);
925
  }
926

    
927
  if (!$handler) {
928
    return '';
929
  }
930

    
931
  $entity_info = entity_get_info($handler->entity_type);
932

    
933
  $title = $entity_info['label'];
934

    
935
  if (strpos($bundle, '.') === FALSE) {
936
    $bundle = $bundle;
937
    $view_mode = '';
938
  }
939
  else {
940
    list($bundle, $view_mode) = explode('.', $bundle);
941
  }
942

    
943
  $title .= ' | ' . $handler->get_bundle_title($bundle);
944

    
945
  if ($view_mode && !empty($handler->plugin['view modes'][$view_mode]['label'])) {
946
    $title .= ' | ' . $handler->plugin['view modes'][$view_mode]['label'];
947
  }
948

    
949
  return $title;
950
}
951

    
952
/**
953
 * Menu callback to determine if a type has a choice of defaults.
954
 *
955
 * We use this to make sure the right tabs appear.
956
 */
957
function panelizer_has_choice_callback($handler, $bundle, $name = NULL) {
958
  if (is_string($handler)) {
959
    $handler = panelizer_entity_plugin_get_handler($handler);
960
  }
961

    
962
  if (empty($handler)) {
963
    return FALSE;
964
  }
965

    
966
  if (!panelizer_administer_entity_bundle($handler, $bundle)) {
967
    return FALSE;
968
  }
969

    
970
  // Check to see if $name is valid.
971
  if (!empty($name) && !$handler->get_default_panelizer_object($bundle, $name)) {
972
    return FALSE;
973
  }
974

    
975
  return $handler->has_panel_choice($bundle);
976
}
977

    
978
/**
979
 * Menu callback to determine if a type+view_mode has a choice of defaults.
980
 */
981
function panelizer_has_choice_callback_view_mode($handler, $bundle, $view_mode) {
982
  return panelizer_has_choice_callback($handler, $bundle . '.' . $view_mode);
983
}
984

    
985
/**
986
 * Menu callback to determine if a type has a choice of defaults.
987
 *
988
 * Use to make sure the right tabs appear.
989
 */
990
function panelizer_has_no_choice_callback($handler, $bundle, $view_mode = NULL) {
991
  if (is_string($handler)) {
992
    $handler = panelizer_entity_plugin_get_handler($handler);
993
  }
994

    
995
  if (empty($handler)) {
996
    return FALSE;
997
  }
998

    
999
  if (!empty($view_mode)) {
1000
    $bundle .= '.' . $view_mode;
1001
  }
1002

    
1003
  if (!panelizer_administer_entity_bundle($handler, $bundle)) {
1004
    return FALSE;
1005
  }
1006

    
1007
  return !$handler->has_panel_choice($bundle);
1008
}
1009

    
1010
/**
1011
 * Menu callback to determine if a type has a choice of defaults.
1012
 *
1013
 * Used to make sure the right tabs appear.
1014
 */
1015
function panelizer_is_panelized($handler, $bundle, $view_mode = NULL) {
1016
  if (is_string($handler)) {
1017
    $handler = panelizer_entity_plugin_get_handler($handler);
1018
  }
1019

    
1020
  if (!$handler) {
1021
    return FALSE;
1022
  }
1023

    
1024
  if ($view_mode) {
1025
    $bundle .= '.' . $view_mode;
1026
  }
1027

    
1028
  if (!panelizer_administer_entity_bundle($handler, $bundle)) {
1029
    return FALSE;
1030
  }
1031

    
1032
  return $handler->is_panelized($bundle);
1033
}
1034

    
1035
/**
1036
 * Access callback to see if a user can administer a particular bundle.
1037
 */
1038
function panelizer_administer_entity_bundle($handler, $bundle) {
1039
  if (is_string($handler)) {
1040
    $handler = panelizer_entity_plugin_get_handler($handler);
1041
  }
1042

    
1043
  // Adjust for the presence of a view mode.
1044
  if (strpos($bundle, '.') !== FALSE) {
1045
    list($bundle, $view_mode) = explode('.', $bundle);
1046
  }
1047

    
1048
  return user_access('administer panelizer') || user_access("administer panelizer $handler->entity_type $bundle defaults");
1049
}
1050

    
1051
/**
1052
 * Access callback to see if a user can administer a particular default.
1053
 */
1054
function panelizer_administer_panelizer_default($handler, $bundle, $name, $view_mode = NULL) {
1055
  if (is_string($handler)) {
1056
    $handler = panelizer_entity_plugin_get_handler($handler);
1057
  }
1058

    
1059
  if ($view_mode) {
1060
    $bundle .= '.' . $view_mode;
1061
  }
1062

    
1063
  $panelizer = $handler->get_default_panelizer_object($bundle, $name);
1064
  if (!$panelizer) {
1065
    return FALSE;
1066
  }
1067

    
1068
  return $handler->access_default_panelizer_object($panelizer);
1069
}
1070

    
1071
/**
1072
 * Menu load callback to scrub a node bundle from the URL safe equivalent.
1073
 */
1074
function panelizer_node_type_load($name) {
1075
  if ($type = node_type_get_type(strtr($name, array('-' => '_')))) {
1076
    return $type->type;
1077
  }
1078
}
1079

    
1080
// ---------------------------------------------------------------------------
1081
// export.inc callbacks to handle proper in/out of our defaults.
1082

    
1083
/**
1084
 * export.inc callback to properly save a panelizer default.
1085
 */
1086
function panelizer_export_save_callback(&$object) {
1087
  if (!empty($object->display)) {
1088
    $object->display->storage_id = $object->name;
1089
    // First write the display.
1090
    panels_save_display($object->display);
1091

    
1092
    // Make sure we have the did.
1093
    $object->did = $object->display->did;
1094
  }
1095

    
1096
  // Then write the default
1097
  if ($object->export_type & EXPORT_IN_DATABASE) {
1098
    // Existing record.
1099
    $update = array('pnid');
1100
  }
1101
  else {
1102
    // New record.
1103
    $update = array();
1104
    $object->export_type = EXPORT_IN_DATABASE;
1105
  }
1106

    
1107
  // Reset the entity's cache. If the EntityCache module is enabled, this also
1108
  // resets its permanent cache.
1109
  list($entity_type, ) = explode(':', $object->name);
1110
  entity_get_controller($entity_type)->resetCache();
1111

    
1112
  return drupal_write_record('panelizer_defaults', $object, $update);
1113
}
1114

    
1115
/**
1116
 * export.inc callback to properly export a panelizer default.
1117
 */
1118
function panelizer_export_export_callback($object, $indent) {
1119
  $object->did = NULL;
1120
  $output = ctools_export_object('panelizer_defaults', $object, $indent);
1121
  $output .= panels_export_display($object->display, $indent);
1122
  $output .= $indent . '$panelizer->display = $display;' . "\n";
1123

    
1124
  return $output;
1125
}
1126

    
1127
/**
1128
 * export.inc callback to properly delete a panelizer default.
1129
 */
1130
function panelizer_export_delete_callback($object) {
1131
  if (!empty($object->did)) {
1132
    panels_delete_display($object->did);
1133
  }
1134

    
1135
  // Allow modules to react on a default Panelizer object before deletion.
1136
  // Triggers hook_panelizer_delete_default().
1137
  module_invoke_all('panelizer_delete_default', $object);
1138

    
1139
  db_delete('panelizer_defaults')
1140
    ->condition('name', $object->name)
1141
    ->execute();
1142
}
1143

    
1144
/**
1145
 * export.inc callback to delete sub records for an object.
1146
 */
1147
function panelizer_export_delete_callback_subrecords($objects) {
1148
  $dids = array();
1149
  foreach ($objects as $panelizer) {
1150
    if (!empty($panelizer->did)) {
1151
      $dids[$panelizer->did] = $panelizer->did;
1152
    }
1153
  }
1154

    
1155
  if ($dids) {
1156
    $displays = panels_load_displays($dids);
1157
    foreach ($objects as $panelizer) {
1158
      if (!empty($panelizer->did) && !empty($displays[$panelizer->did])) {
1159
        $panelizer->display = $displays[$panelizer->did];
1160
      }
1161
    }
1162
  }
1163
}
1164

    
1165
// ---------------------------------------------------------------------------
1166
// Context cache callbacks -- this really needs a less lame system someday.
1167

    
1168
/**
1169
 * Fetch the panelizer object from the object cache.
1170
 *
1171
 * CTools clumsy context editing system requires caching. This lets us do it
1172
 * reasonably.
1173
 *
1174
 * @param $entity_type
1175
 *   Can be something like 'node' or 'user' or 'default'.
1176
 * @param $key
1177
 *   Depends on the $entity_type. Can be a nid, a uid or a default key.
1178
 */
1179
function panelizer_context_cache_get($entity_type, $key) {
1180
  ctools_include('object-cache');
1181
  $cache = ctools_object_cache_get('panelizer_context_cache', $entity_type . ':' . $key);
1182
  if (!empty($cache)) {
1183
    $cache->cached = TRUE;
1184
    return $cache;
1185
  }
1186

    
1187
  if ($entity_type == 'default') {
1188
    list($entity_type, $bundle, $name) = @explode(':', $key, 3);
1189
    $get_default = TRUE;
1190
  }
1191

    
1192
  if ($handler = panelizer_entity_plugin_get_handler($entity_type)) {
1193
    if (!empty($get_default)) {
1194
      $panelizer = $handler->get_default_panelizer_object($bundle, $name);
1195
      $panelizer->base_contexts = $handler->get_base_contexts();
1196
      return $panelizer;
1197
    }
1198
    else {
1199
      list($entity_id, $view_mode) = explode('.', $key);
1200
      $entities = entity_load($entity_type, array($entity_id));
1201
      if (!empty($entities[$entity_id]) && !empty($entities[$entity_id]->panelizer[$view_mode])) {
1202
        $panelizer = $entities[$entity_id]->panelizer[$view_mode];
1203
        $panelizer->base_contexts = $handler->get_base_contexts($entities[$entity_id]);
1204
        return $panelizer;
1205
      }
1206
    }
1207
  }
1208
}
1209

    
1210
/**
1211
 * Store the panelizer object in the object cache.
1212
 *
1213
 * CTools clumsy context editing system requires caching. This lets us do it
1214
 * reasonably.
1215
 *
1216
 * @param $entity_type
1217
 *   Can be something like 'node' or 'user' or 'default'.
1218
 * @param $key
1219
 *   Either the node type or the nid.
1220
 * @param $object
1221
 *   The cached object.
1222
 */
1223
function panelizer_context_cache_set($entity_type, $key, $object) {
1224
  ctools_include('object-cache');
1225
  ctools_object_cache_set('panelizer_context_cache', $entity_type . ':' . $key, $object);
1226
}
1227

    
1228
/**
1229
 * Clear the panelizer object in the object cache.
1230
 *
1231
 * CTools clumsy context editing system requires caching. This lets us do it
1232
 * reasonably.
1233
 *
1234
 * @param $entity_type
1235
 *   Can be something like 'node' or 'user' or 'default'.
1236
 * @param $key
1237
 *   Either the node type or the nid.
1238
 */
1239
function panelizer_context_cache_clear($entity_type, $key) {
1240
  ctools_include('object-cache');
1241
  ctools_object_cache_clear('panelizer_context_cache', $entity_type . ':' . $key);
1242
}
1243

    
1244
// --------------------------------------------------------------------------
1245
// Panels edit cache contexts.
1246

    
1247
/**
1248
 * Implements hook_panels_cache_get().
1249
 *
1250
 * Get display edit cache for a display being edited.
1251
 *
1252
 * The key is the second half of the key in this form: panelizer:TYPE:KEY
1253
 */
1254
function panelizer_panels_cache_get($argument) {
1255
  ctools_include('object-cache');
1256
  list($entity_type, $key) = explode(':', $argument, 2);
1257
  $cache = ctools_object_cache_get('panelizer_display_cache', $entity_type . ':' . $key);
1258

    
1259
  // Keep $type because $entity_type can be 'default' which is not actually an
1260
  // entity type in that case.
1261
  $type = $entity_type;
1262
  if ($entity_type == 'default') {
1263
    list($entity_type, $bundle, $name) = @explode(':', $key, 3);
1264
    $get_default = TRUE;
1265
  }
1266

    
1267
  $handler = panelizer_entity_plugin_get_handler($entity_type);
1268
  if (!$handler) {
1269
    return;
1270
  }
1271

    
1272
  // Extract the entity ID and view mode.
1273
  list($entity_id, $view_mode) = explode(':', $key, 2);
1274
  // If this entity supports revisions, and a custom revision is being
1275
  // displayed, it's possible for the key to also include the revision ID.
1276
  if ($handler->supports_revisions && strpos($view_mode, ':') !== FALSE) {
1277
    list($entity_id, $view_mode, $vid) = explode(':', $key);
1278
  }
1279

    
1280
  // If it's already cached, we still need to restore our contexts.
1281
  if (!empty($cache)) {
1282
    $cache->cached = TRUE;
1283
    if (!empty($get_default)) {
1284
      $panelizer = $handler->get_default_panelizer_object($bundle, $name);
1285
      $cache->display->context = $handler->get_contexts($panelizer);
1286

    
1287
      // Set the storage_type and storage_id if either is empty.
1288
      if (empty($cache->display->storage_type)) {
1289
        $cache->display->storage_type = 'panelizer_default';
1290
      }
1291
      if (empty($cache->display->storage_id)) {
1292
        $cache->display->storage_id = $panelizer->name;
1293
      }
1294
    }
1295
    else {
1296
      $conditions = (isset($vid) ? array('vid' => $vid) : array());
1297
      $entities = entity_load($entity_type, array($entity_id), $conditions);
1298
      if (!empty($entities[$entity_id]) && !empty($entities[$entity_id]->panelizer[$view_mode])) {
1299
        $panelizer = $entities[$entity_id]->panelizer[$view_mode];
1300
        $cache->display->context = $handler->get_contexts($panelizer, $entities[$entity_id]);
1301
      }
1302
    }
1303

    
1304
    return $cache;
1305
  }
1306

    
1307
  $cache = new stdClass();
1308

    
1309
  // If it wasn't cached, create a new cache.
1310
  if (!empty($get_default)) {
1311
    $panelizer = $handler->get_default_panelizer_object($bundle, $name);
1312
    $cache->display = $panelizer->display;
1313
    $cache->display->context = $handler->get_contexts($panelizer);
1314
    
1315
    // Set the storage_type and storage_id if either is empty.
1316
     if (empty($cache->display->storage_type)) {
1317
       $cache->display->storage_type = 'panelizer_default';
1318
     }
1319
     if (empty($cache->display->storage_id)) {
1320
       $cache->display->storage_id = $panelizer->name;
1321
     }
1322
  }
1323
  else {
1324
    $conditions = (isset($vid) ? array('vid' => $vid) : array());
1325
    $entities = entity_load($entity_type, array($entity_id), $conditions);
1326
    if (empty($entities[$entity_id]) || empty($entities[$entity_id]->panelizer[$view_mode])) {
1327
      return $cache;
1328
    }
1329

    
1330
    list($entity_id, $revision_id, $bundle) = entity_extract_ids($entity_type, $entities[$entity_id]);
1331
    $panelizer = $entities[$entity_id]->panelizer[$view_mode];
1332
    $cache->display = $panelizer->display;
1333
    $cache->display->context = $handler->get_contexts($panelizer, $entities[$entity_id]);
1334
  }
1335

    
1336
  ctools_include('common', 'panels');
1337
  ctools_include('plugins', 'panels');
1338

    
1339
  $cache_keys = array(
1340
    'panelizer',
1341
    $type,
1342
    $key,
1343
  );
1344
  if (isset($vid) && is_numeric($vid) && substr($key, strlen($vid) * -1) != $vid) {
1345
    $cache_keys[] = $vid;
1346
  }
1347
  $cache->display->cache_key = implode(':', $cache_keys);
1348

    
1349
  // Set the allowed content types.
1350
  if (variable_get('panelizer_' . $type . ':' . $bundle . '_allowed_types_default', FALSE)) {
1351
    $cache->content_types = panels_common_get_allowed_types('panels_page', $cache->display->context);
1352
  }
1353
  else {
1354
    $cache->content_types = panels_common_get_allowed_types('panelizer_' . $type . ':' . $bundle, $cache->display->context);
1355
  }
1356

    
1357
  // Set the allowed layout options.
1358
  $cache->display->allowed_layouts = panels_common_get_allowed_layouts(panelizer_get_allowed_layouts_option($type, $bundle));
1359

    
1360
  return $cache;
1361
}
1362

    
1363
/**
1364
 * Implements hook_panels_cache_set().
1365
 *
1366
 * Store a display edit in progress in the page cache.
1367
 */
1368
function panelizer_panels_cache_set($argument, $cache) {
1369
  ctools_include('object-cache');
1370
  ctools_object_cache_set('panelizer_display_cache', $argument, $cache);
1371
}
1372

    
1373
/**
1374
 * Implements hook_panels_cache_clear().
1375
 *
1376
 * Save all changes made to a display using the Page Manager page cache.
1377
 */
1378
function panelizer_panels_cache_clear($argument, $cache) {
1379
  ctools_include('object-cache');
1380
  ctools_object_cache_clear('panelizer_display_cache', $argument);
1381
}
1382

    
1383
/**
1384
 * Implements hook_panels_cache_save().
1385
 *
1386
 * Save all changes made to a display using the Page Manager page cache.
1387
 */
1388
function panelizer_panels_cache_save($argument, $cache) {
1389
  // If this is set, they clicked a button that saves a different panelizer
1390
  // than was being edited, such as saving to default rather than customizing
1391
  // an entity.
1392
  $original = $argument;
1393
  if (isset($cache->display->swap_cache_key)) {
1394
    $argument = $cache->display->swap_cache_key;
1395
  }
1396

    
1397
  list($entity_type, $key) = explode(':', $argument, 2);
1398
  $type = $entity_type;
1399
  if ($entity_type == 'default') {
1400
    list($entity_type, $bundle, $name) = @explode(':', $key, 3);
1401
    $get_default = TRUE;
1402
  }
1403

    
1404
  $handler = panelizer_entity_plugin_get_handler($entity_type);
1405
  if (!$handler) {
1406
    return;
1407
  }
1408

    
1409
  if (!empty($get_default)) {
1410
    $panelizer = $handler->get_default_panelizer_object($bundle, $name);
1411
    $panelizer->display = $cache->display;
1412
    ctools_include('export');
1413
    ctools_export_crud_save('panelizer_defaults', $panelizer);
1414
  }
1415
  else {
1416
    list($entity_id, $view_mode) = explode(':', $key);
1417
    $conditions = (isset($vid) ? array('vid' => $vid) : array());
1418
    $entities = entity_load($entity_type, array($entity_id), $conditions);
1419
    if ($entities[$entity_id] && $entities[$entity_id]->panelizer[$view_mode]) {
1420
      $entities[$entity_id]->panelizer[$view_mode]->display = $cache->display;
1421
      $entities[$entity_id]->panelizer[$view_mode]->display_is_modified = TRUE;
1422
      $handler->entity_save($entities[$entity_id]);
1423
      // The display may have been cloned in the save process, so need to be
1424
      // sure to put the old display back, and its contexts.
1425
      $cache->display = $entities[$entity_id]->panelizer[$view_mode]->display;
1426
      $cache->display->context = $handler->get_contexts($entities[$entity_id]->panelizer[$view_mode], $entities[$entity_id]);
1427
    }
1428
  }
1429
  panelizer_panels_cache_clear($original, $cache);
1430
}
1431

    
1432
// ---------------------------------------------------------------------------
1433
// Contrib module hooks to provide needed functionality.
1434

    
1435
/**
1436
 * Implements hook_export_node_alter().
1437
 *
1438
 * Integrate with export.module for saving panel_nodes into code.
1439
 */
1440
function panelizer_export_node_alter(&$node, $original_node, $method) {
1441
  // @todo
1442
}
1443

    
1444
/**
1445
 * Implements hook_panelizer_defaults_alter().
1446
 *
1447
 * Remove the panels node because there is no point to panelizing it.
1448
 */
1449
function panelizer_panelizer_default_types_alter(&$bundles, $entity_type) {
1450
  switch ($entity_type) {
1451
    case 'node':
1452
      // Disallow the panel node type, since it's already a panel.
1453
      if (module_exists('panels_node') && !empty($bundles['panel'])) {
1454
        unset($bundles['panel']);
1455
      }
1456
      break;
1457
  }
1458
}
1459

    
1460
/**
1461
 * Implements hook_features_pipe_panelizer_defaults_alter().
1462
 */
1463
function panelizer_features_pipe_panelizer_defaults_alter(&$more, $data, $export) {
1464
  foreach ($data as $machine_name) {
1465
    list ($entity_type, $bundle) = explode(':', $machine_name);
1466

    
1467
    $variables = array(
1468
      'panelizer_defaults_' . $entity_type . '_' . $bundle,
1469
      'panelizer_' . $entity_type . ':' . $bundle . '_allowed_layouts',
1470
      'panelizer_' . $entity_type . ':' . $bundle . '_allowed_layouts_default',
1471
      'panelizer_' . $entity_type . ':' . $bundle . '_allowed_types',
1472
      'panelizer_' . $entity_type . ':' . $bundle . '_allowed_types_default',
1473
      'panelizer_' . $entity_type . ':' . $bundle . '_default',
1474
    );
1475

    
1476
    // Add default display variables for each view mode.
1477
    $entity_info = entity_get_info($entity_type);
1478
    $default_base = 'panelizer_' . $entity_type . ':' . $bundle . ':';
1479
    foreach ($entity_info['view modes'] as $view_mode => $view_info) {
1480
      $variables[] = $default_base . $view_mode . '_selection';
1481
    }
1482
    $variables[] = $default_base . 'page_manager' . '_selection';
1483
    $variables[] = $default_base . 'default' . '_selection';
1484

    
1485
    foreach ($variables as $variable) {
1486
      $more['variable'][$variable] = $variable;
1487
    }
1488
  }
1489

    
1490
  return $more;
1491
}
1492

    
1493
/**
1494
 * Implements hook_search_api_alter_callback_info().
1495
 */
1496
function panelizer_search_api_alter_callback_info() {
1497
  $info = array();
1498
  $info['panelizer'] = array(
1499
    'name' => t('Panelizer'),
1500
    'description' => t('Add the content from the Panelizer "Full page override" to the search index.'),
1501
    'class' => 'PanelizerSearchApiAlterCallback',
1502
  );
1503
  return $info;
1504
}
1505

    
1506
// -----------------------------------------------------------------------
1507
// Theme functions where necessary.
1508

    
1509
/**
1510
 * Panelizer view mode theme function.
1511
 */
1512
function template_preprocess_panelizer_view_mode(&$vars) {
1513
  $element = $vars['element'];
1514
  $entity = $element['#panelizer_entity'];
1515
  $panelizer = $element['#panelizer'];
1516
  $handler = $element['#panelizer_handler'];
1517
  $info = $element['#panelizer_content'];
1518

    
1519
  $handler->preprocess_panelizer_view_mode($vars, $entity, $element, $panelizer, $info);
1520
}
1521

    
1522
// -----------------------------------------------------------------------
1523
// Drupal actions integration for VBO.
1524

    
1525
/**
1526
 * Implements hook_action_info().
1527
 */
1528
function panelizer_action_info() {
1529
  return array(
1530
    'panelizer_set_status_action' => array(
1531
      'type' => 'entity',
1532
      'label' => t('Set panelizer status'),
1533
      'vbo_configurable' => TRUE,
1534
      'configurable' => FALSE,
1535
      'behavior' => array('changes_property'),
1536
      'configurable' => TRUE,
1537
    )
1538
  );
1539
}
1540

    
1541
/**
1542
 * Executes the panelizer_set_status action.
1543
 */
1544
function panelizer_set_status_action($entity, $context) {
1545
  $view_mode = 'page_manager';
1546
  if (isset($context['view_mode'])) {
1547
    $view_mode = $context['view_mode'];
1548
  }
1549

    
1550
  list($entity_id, $revision_id, $bundle) = entity_extract_ids($context['entity_type'], $entity);
1551
  if (isset($context['panelizer_default'])) {
1552
    $entity->panelizer[$view_mode] = $context['panelizer_default'];
1553
    $entity->panelizer[$view_mode]->did = NULL;
1554

    
1555
    // Ensure original values are maintained.
1556
    $entity->panelizer[$view_mode]->entity_id = $entity_id;
1557
    $entity->panelizer[$view_mode]->revision_id = $revision_id;
1558
  }
1559
  else {
1560
    $entity->panelizer[$view_mode]->name = NULL;
1561
    $entity->panelizer[$view_mode]->did = NULL;
1562
  }
1563
}
1564

    
1565
/**
1566
 * Provides the panelizer_set_status_action form.
1567
 */
1568
function panelizer_set_status_action_form($context, &$form_state) {
1569
  $form = array();
1570
  $entity_info = entity_get_info($context['entity_type']);
1571
  $entities = entity_load($context['entity_type'], $form_state['selection']);
1572
  $bundles = array();
1573

    
1574
  $handler = panelizer_entity_plugin_get_handler($context['entity_type']);
1575
  // Collect our list of bundles.
1576
  foreach ($entities as $entity) {
1577
    list($entity_id, $revision_id, $bundle) = entity_extract_ids($context['entity_type'], $entity);
1578
    $bundles[$bundle] = $bundle;
1579
  }
1580

    
1581
  $conditions = array(
1582
    'panelizer_type' => $context['entity_type'],
1583
    'panelizer_key' => $bundles,
1584
  );
1585

    
1586
  ctools_include('export');
1587
  $defaults = ctools_export_load_object('panelizer_defaults', 'conditions', $conditions);
1588

    
1589
  foreach ($defaults as $name => $default) {
1590
    if (empty($default->title)) {
1591
      $default->title = t('Default');
1592
    }
1593
    $options[$default->view_mode][$name] = t('@bundle: @title', array('@bundle' => $entity_info['bundles'][$default->panelizer_key]['label'], '@title' => $default->title));
1594
  }
1595

    
1596
  $view_modes = array();
1597
  foreach ($handler->plugin['view modes'] as $view_mode => $view_mode_info) {
1598
    $view_modes[$view_mode] = $view_mode_info['label'];
1599
  }
1600

    
1601
  $form['panelizer']['#tree'] = TRUE;
1602

    
1603
  foreach ($view_modes as $view_mode => $label) {
1604
    if (empty($options[$view_mode])) {
1605
      unset($view_modes[$view_mode]);
1606
      continue;
1607
    }
1608

    
1609
    natcasesort($options[$view_mode]);
1610
    $panelizers = array(
1611
      'not' => t('Not panelized'),
1612
    ) + $options[$view_mode];
1613

    
1614
    $form['panelizer'][$view_mode] = array(
1615
      '#type' => 'select',
1616
      '#title' => t('Panelizer status'),
1617
      '#options' => $panelizers,
1618
      '#states' => array(
1619
        'visible' => array(
1620
          '#panelizer-view-mode' => array('value' => $view_mode),
1621
        ),
1622
      ),
1623
    );
1624
  }
1625

    
1626
  $form['view_mode'] = array(
1627
    '#type' => 'select',
1628
    '#title' => t('View mode'),
1629
    '#options' => $view_modes,
1630
    '#id' => 'panelizer-view-mode',
1631
    '#weight' => -10,
1632
  );
1633

    
1634
  $form['#panelizer_defaults'] = $defaults;
1635
  return $form;
1636
}
1637

    
1638
/**
1639
 * FormAPI submission callback.
1640
 */
1641
function panelizer_set_status_action_submit($form, $form_state) {
1642
  $view_mode = $form_state['values']['view_mode'];
1643
  $panelizer = $form_state['values']['panelizer'][$view_mode];
1644

    
1645
  $retval = array(
1646
    'panelizer' => $panelizer,
1647
    'view_mode' => $view_mode,
1648
  );
1649

    
1650
  if ($form_state['values']['panelizer'] != 'not') {
1651
    $retval['panelizer_default'] = $form['#panelizer_defaults'][$panelizer];
1652
  }
1653

    
1654
  return $retval;
1655
}
1656

    
1657
// --------------------------------------------------------------------------
1658
// Miscellaneous helper functions
1659

    
1660
/**
1661
 * Return list of operations.
1662
 *
1663
 * @see hook_panelizer_operations_alter().
1664
 */
1665
function panelizer_operations() {
1666
  $operations = array(
1667
    'settings' => array(
1668
      'menu title' => 'Settings',
1669
      'link title' => t('settings'),
1670
      'admin callback' => 'panelizer_default_settings_page',
1671
      // ctools export ui thinks this is 'edit'.
1672
      'ui path' => 'edit',
1673
    ),
1674
    'context' => array(
1675
      'menu title' => 'Context',
1676
      'link title' => t('context'),
1677
      'admin callback' => 'panelizer_default_context_page',
1678
    ),
1679
    'layout' => array(
1680
      'menu title' => 'Layout',
1681
      'link title' => t('layout'),
1682
      'admin callback' => 'panelizer_default_layout_page',
1683
    ),
1684
    'content' => array(
1685
      'menu title' => 'Content',
1686
      'link title' => t('content'),
1687
      'admin callback' => 'panelizer_default_content_page',
1688
    ),
1689
  );
1690

    
1691
  drupal_alter('panelizer_operations', $operations);
1692

    
1693
  return $operations;
1694
}
1695

    
1696
/**
1697
 * Gets the current layout options approach for an entity bundle.
1698
 *
1699
 * @param string $type
1700
 *   The entity type.
1701
 * @param string $bundle
1702
 *   The entity bundle.
1703
 *
1704
 * @return string
1705
 *   The name of the layout approach to check (default or per bundle).
1706
 */
1707
function panelizer_get_allowed_layouts_option($type, $bundle) {
1708
  if (variable_get('panelizer_' . $type . ':' . $bundle . '_allowed_layouts_default', FALSE)) {
1709
    return 'panels_page';
1710
  }
1711
  else {
1712
    return 'panelizer_' . $type . ':' . $bundle;
1713
  }
1714
}
1715

    
1716
/**
1717
 * Implements hook_form_FORM_ID_alter() for panels_ipe_edit_control_form().
1718
 *
1719
 * Alter the IPE save control form to handle extra Panelizer functionality.
1720
 */
1721
function panelizer_form_panels_ipe_edit_control_form_alter(&$form, &$form_state) {
1722
  if (empty($form_state['renderer'])) {
1723
    return;
1724
  }
1725

    
1726
  $renderer = $form_state['renderer'];
1727

    
1728
  $cache_key = $renderer->display->cache_key;
1729
  $parts = explode(':', $cache_key, 3);
1730
  if ($parts[0] != 'panelizer') {
1731
    return;
1732
  }
1733

    
1734
  list($module, $type, $key) = $parts;
1735

    
1736
  if ($type == 'default') {
1737
    return;
1738
  }
1739

    
1740
  // Load the $plugin information.
1741
  $handler = panelizer_entity_plugin_get_handler($type);
1742
  if (!$handler) {
1743
    return;
1744
  }
1745

    
1746
  // Get the entity that's being edited.
1747
  list($entity_id, $view_mode) = explode(':', $key);
1748
  $entities = entity_load($handler->entity_type, array($entity_id));
1749
  if (empty($entities[$entity_id])) {
1750
    return;
1751
  }
1752

    
1753
  $entity = $entities[$entity_id];
1754
  list($entity_id, $revision_id, $bundle) = entity_extract_ids($handler->entity_type, $entity);
1755
  $entity_info = entity_get_info($handler->entity_type);
1756

    
1757
  if (empty($entity->panelizer[$view_mode])) {
1758
    return;
1759
  }
1760

    
1761
  $panelizer = $entities[$entity_id]->panelizer[$view_mode];
1762

    
1763
  module_load_include('inc', 'panelizer', 'includes/common');
1764
  $revision_info = $handler->entity_allows_revisions($entity);
1765

    
1766
  // Set panelizer info regardless of revision or panelizer layout default
1767
  // status.
1768
  $form_state['panelizer entity'] = $entity;
1769
  $form_state['panelizer bundle'] = $bundle;
1770
  $form_state['panelizer handler'] = $handler;
1771
  $form_state['panelizer view_mode'] = $view_mode;
1772

    
1773
  // If this entity has revisions enabled we can assume that they have
1774
  // permissions to add revisions via IPE.
1775
  if (!empty($revision_info)) {
1776
    $form_state['entity'] = $entity;
1777
    $form_state['revision info'] = $revision_info;
1778
    panelizer_add_revision_info_form($form, $form_state);
1779
    // Tweak the log message field to make it fit better.
1780
    if (isset($form['revision_information']['log'])) {
1781
      $form['revision_information']['log']['#type'] = 'textfield';
1782
      $form['revision_information']['log']['#description'] = '';
1783
    }
1784
  }
1785

    
1786
  // If the entity already has customized panelizer data, add the revert button.
1787
  if (!empty($panelizer->did)) {
1788
    if ($handler->has_default_panel($bundle . '.' . $view_mode)) {
1789
      $uri = entity_uri($handler->entity_type, $entity);
1790
      $url = $uri['path'];
1791
      // Support for Workbench Moderation to redirect to the newest revision for
1792
      // this node.
1793
      if ($handler->entity_type == 'node' && module_exists('workbench_moderation')) {
1794
        $url = 'node/' . $entity->nid . '/current-revision';
1795
      }
1796
      $redirect_url = url($uri['path'] . '/panelizer/' . $view_mode . '/reset', array('query' => array('destination' => $url)));
1797
      drupal_add_js(array('panelizer' => array('revert_default_url' => $redirect_url)), 'setting');
1798

    
1799
      $form['buttons']['revert_default'] = array(
1800
        '#type' => 'submit',
1801
        '#value' => t('Revert to @bundle_name default', array('@bundle_name' => $entity_info['bundles'][$bundle]['label'])),
1802
        '#submit' => array('panels_ipe_revert_to_default'),
1803
        '#attributes' => array('class' => array('panels-ipe-cancel')),
1804
        '#id' => 'panelizer-ipe-revert',
1805
        '#access' => $handler->panelizer_access('defaults', $entity, $panelizer->view_mode),
1806
      );
1807
    }
1808
    return;
1809
  }
1810

    
1811
  // Change the default button to say "Save as custom".
1812
  $form['buttons']['submit']['#value'] = t('Save as custom');
1813

    
1814
  // Calculate the proper name to add to the cache key, which has some data
1815
  // stripped off of the true name.
1816
  $name = 'default';
1817
  if (!empty($panelizer->name)) {
1818
    $pieces = explode(':', $panelizer->name);
1819
    if (isset($pieces[2])) {
1820
      $name = $pieces[2];
1821
    }
1822
  }
1823

    
1824
  // Add another button to save as the default instead.
1825
  $form['buttons']['save_default'] = array(
1826
    '#type' => 'submit',
1827
    '#value' => t('Save as @bundle_name default', array('@bundle_name' => $entity_info['bundles'][$bundle]['label'])),
1828
    '#submit' => array('panels_ipe_change_to_default', 'panels_edit_display_form_submit'),
1829
    '#save-display' => TRUE,
1830
    '#weight' => -1,
1831
    // Precalculate the cache key so we don't have to unwind a bunch of stuff in
1832
    // the submit handler.
1833
    '#cache_key' => 'default:' . $handler->entity_type . ':' . $bundle . '.' . $panelizer->view_mode . ':' . $name,
1834
    '#attributes' => array('class' => array('panels-ipe-save')),
1835
    '#id' => 'panelizer-save-default',
1836
    '#access' => $handler->panelizer_access('defaults', $entity, $panelizer->view_mode),
1837
  );
1838
}
1839

    
1840
/**
1841
 * Implements hook_form_FORM_ID_alter() for panels_change_layout().
1842
 *
1843
 * Alter the change layout form to support saving as default.
1844
 */
1845
function panelizer_form_panels_change_layout_alter(&$form, &$form_state) {
1846
  // Only alter on initial form build.
1847
  if (empty($form_state['executed'])) {
1848
    if (isset($form_state['back'])) {
1849
      // Do nothing when moving backwards.
1850
      return;
1851
    }
1852

    
1853
    // Extract the display from the form state.
1854
    $display = $form_state['display'];
1855

    
1856
    $cache_key = $display->cache_key;
1857
    $parts = explode(':', $cache_key, 3);
1858
    if ($parts[0] != 'panelizer') {
1859
      return;
1860
    }
1861

    
1862
    list($module, $type, $key) = $parts;
1863

    
1864
    // If the display is not owned by Panelizer, or is default handler, exit.
1865
    if ($module != 'panelizer' || $type == 'default') {
1866
      return;
1867
    }
1868

    
1869
    // Load the $plugin information.
1870
    $handler = panelizer_entity_plugin_get_handler($type);
1871
    if (!$handler) {
1872
      return;
1873
    }
1874

    
1875
    // Get the entity that's being edited through Panelizer context.
1876
    $entity = $display->context['panelizer']->data;
1877

    
1878
    // Check if the view mode is configured.
1879
    list($entity_id, $view_mode) = explode(':', $key);
1880
    if (empty($entity->panelizer[$view_mode])) {
1881
      return;
1882
    }
1883

    
1884
    list($entity_id, $revision_id, $bundle) = entity_extract_ids($handler->entity_type, $entity);
1885
    $entity_info = entity_get_info($handler->entity_type);
1886

    
1887
    $panelizer = $entity->panelizer[$view_mode];
1888

    
1889
    // Calculate the proper name to add to the cache key, which has some data
1890
    // stripped off of the true name.
1891
    $name = 'default';
1892
    if (!empty($panelizer->name)) {
1893
      $pieces = explode(':', $panelizer->name);
1894
      if (isset($pieces[2])) {
1895
        $name = $pieces[2];
1896
      }
1897
    }
1898

    
1899
    // Change the default button to say "Save as custom".
1900
    $form['submit']['#value'] = t('Save as custom');
1901

    
1902
    // Add another button to save as the default instead.
1903
    $form['save_default'] = array(
1904
      '#type' => 'submit',
1905
      '#value' => t('Save as @bundle_name default', array('@bundle_name' => $entity_info['bundles'][$bundle]['label'])),
1906
      '#submit' => array('panels_ipe_change_to_default', 'panels_change_layout_submit'),
1907
      '#save-display' => TRUE,
1908
      '#cache_key' => 'default:' . $handler->entity_type . ':' . $bundle . '.' . $panelizer->view_mode . ':' . $name,
1909
      '#access' => $handler->panelizer_access('defaults', $entity, $panelizer->view_mode),
1910
    );
1911
  }
1912
}
1913

    
1914
/**
1915
 * Implement template_preprocess_panels_ipe_toolbar().
1916
 */
1917
function panelizer_preprocess_panels_ipe_toolbar(&$variables) {
1918
  // Some custom CSS to improve the UX.
1919
  // $variables['#attached'] = array(
1920
  //   'css' => array(
1921
  //     drupal_get_path('module', 'panelizer') . '/css/panelizer.ipe.css',
1922
  //   ),
1923
  // );
1924
  // dpm($variables);
1925
}
1926

    
1927
/**
1928
 * Implements hook_panels_ipe_ajax_save_commands_alter().
1929
 *
1930
 * If Workbench Moderation is enabled, and this is for the form submission on a
1931
 * Panelized node, redirect to the latest revision upon save.
1932
 */
1933
function panelizer_panels_ipe_ajax_save_commands_alter(&$ipe, $form_state) {
1934
  // This requires Workbench Moderation.
1935
  if (module_exists('workbench_moderation')) {
1936
    // The form was actually saved.
1937
    if (!empty($form_state['submitted']) && !empty($ipe->meta_location)) {
1938
      // This is for a revisions-enabled Panelizer entity.
1939
      if (!empty($form_state['use revisions'])) {
1940
        $entity = $form_state['entity'];
1941
        $ipe->commands[0] = ctools_ajax_command_redirect('node/' . $entity->nid . '/current-revision');
1942
      }
1943
    }
1944
  }
1945
}
1946

    
1947
/**
1948
 * Submit handler to save the panelizer default instead of customizing the
1949
 * entity.
1950
 */
1951
function panels_ipe_change_to_default($form, &$form_state) {
1952
  // Change the cache key so that it saves to the default instead of the
1953
  // entity. This works because we're actually editing the original display
1954
  // anyway, and everything else keys off the cache key.
1955
  $form_state['display']->swap_cache_key = $form_state['triggering_element']['#cache_key'];
1956
}
1957

    
1958
/**
1959
 * Submit handler to revert to the default panelizer.
1960
 */
1961
function panels_ipe_revert_to_default($form, &$form_state) {
1962
  // Reduce code complexity due to indirection.
1963
  $handler = $form_state['panelizer handler'];
1964
  $entity = $form_state['panelizer entity'];
1965
  $bundle = $form_state['panelizer bundle'];
1966
  $view_mode = $form_state['panelizer view_mode'];
1967
  $renderer = $form_state['renderer'];
1968

    
1969
  $handler->delete_entity_panelizer($entity, $view_mode);
1970

    
1971
  $name = implode(':', array($handler->entity_type, $bundle, 'default'));
1972
  if ($view_mode != 'page_manager') {
1973
    $name .= ':' . $view_mode;
1974
  }
1975
  $cache_key = $form_state['display']->cache_key;
1976

    
1977
  // Now load the original default display and force a rerender.
1978
  $panelizer = $handler->get_default_panelizer_object($bundle . '.' . $view_mode, $name);
1979

    
1980
  $renderer->display = $display = $panelizer->display;
1981
  $display->cache_key = $cache_key;
1982

    
1983
  $display->context = $handler->get_contexts($panelizer, $entity);
1984

    
1985
  $renderer->commands[] = ajax_command_replace("#panels-ipe-display-{$renderer->clean_key}", panels_render_display($display, $renderer));
1986
}
1987

    
1988
/**
1989
 * Implements hook_panelizer_pre_render_alter().
1990
 *
1991
 * Panelizer fails to communicate to the theme layer what view mode an entity's
1992
 * fields are being rendered in, so we unfortunately have to do that ourselves.
1993
 */
1994
function panelizer_panelizer_pre_render_alter(&$panelizer, &$display, &$entity) {
1995
  foreach ($entity->panelizer as $view_mode => $reference_panelizer) {
1996
    if ($reference_panelizer === $panelizer) {
1997
      $entity->panelizer_view_mode = $view_mode;
1998
      break;
1999
    }
2000
  }
2001
}
2002

    
2003
/**
2004
 * Implements hook_workbench_moderation_node_history_view_alter().
2005
 *
2006
 * This is a little kludgy as the data in the row is stored as final HTML for
2007
 * display.
2008
 */
2009
function panelizer_workbench_moderation_node_history_view_alter(&$rows) {
2010
  // Load the node.
2011
  $node = node_load(arg(1));
2012

    
2013
  // Verify the user has access to the Panelizer configuration.
2014
  if (panelizer_is_panelized('node', $node->type)) {
2015
    // Loop over each table row.
2016
    foreach ($rows as $key => &$row) {
2017
      // Published.
2018
      $path = 'node/' . $node->nid . '/panelizer';
2019

    
2020
      // Not published.
2021
      if (!in_array('published-revision', $row['class'])) {
2022
        $path = 'node/' . $node->nid . '/revisions/' . $row['data']['vid'] . '/panelizer';
2023
      }
2024

    
2025
      // Add a link to the Panelizer page.
2026
      $row['data']['revision'] .= ' | ' . l('Customize display', $path);
2027
    }
2028
  }
2029
}
2030

    
2031
/**
2032
 * Menu callback load method to either return the requested revision ID or FALSE
2033
 * to prevent the tab from being processed.
2034
 *
2035
 * @param string $vid
2036
 *   An entity's revision ID.
2037
 *
2038
 * @return mixed
2039
 *   Either the revision_id or FALSE if the revision was empty.
2040
 */
2041
function panelizer_node_revision_load($revision_id = NULL) {
2042
  if (!empty($revision_id)) {
2043
    return $revision_id;
2044
  }
2045
  return FALSE;
2046
}
2047

    
2048
/**
2049
 * Implements hook_clone_node_alter().
2050
 *
2051
 * Custom integration for Node Clone to handle objects that might be embedded in
2052
 * a custom Panelizer display. Currently supports Fieldable Panels Panes.
2053
 */
2054
function panelizer_clone_node_alter(&$node, $context) {
2055
  if (!empty($node->panelizer)) {
2056
    foreach ($node->panelizer as $view_mode => &$panelizer) {
2057
      // Only deal with custom displays, ignore default displays which would
2058
      // be selected in $panelizer->name.
2059
      if (!empty($panelizer->did) && !empty($panelizer->display)) {
2060
        // Loop over each pane.
2061
        foreach ($panelizer->display->content as &$pane) {
2062
          // Clone each FPP and then assign the new fpid.
2063
          if ($pane->type == 'fieldable_panels_pane') {
2064
            list($subtype, $fpid) = explode(':', $pane->subtype);
2065
            if ($subtype == 'fpid') {
2066
              // Clone the FPP object.
2067
              $fpp = fieldable_panels_panes_load($fpid);
2068

    
2069
              // Clean the some basic settings.
2070
              $fpp->fpid = NULL;
2071
              $fpp->created = NULL;
2072
              $fpp->timestamp = NULL;
2073

    
2074
              // Save the cloned FPP.
2075
              $newfpp = fieldable_panels_panes_save($fpp);
2076

    
2077
              // Update the FPP reference.
2078
              $pane->subtype = 'fpid:' . $newfpp->fpid;
2079
            }
2080
          }
2081
        }
2082
      }
2083
    }
2084
  }
2085
}