Projet

Général

Profil

Paste
Télécharger (65,1 ko) Statistiques
| Branche: | Révision:

root / drupal7 / sites / all / modules / panelizer / panelizer.module @ 1e39edcb

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
  // If a default Panels display has no storage type, set it.
522
  foreach ($items as &$panelizer) {
523
    $display =& $panelizer->display;
524
    if (empty($display->storage_type)) {
525
      $display->storage_type = 'panelizer_default';
526
      $display->storage_id = $panelizer->name;
527
    }
528
  }
529

    
530
  // Allow features_overrides to alter the config.
531
  drupal_alter('panelizer_defaults_override', $items);
532
}
533

    
534
/**
535
 * Implements hook_default_page_manager_handlers().
536
 */
537
function panelizer_default_page_manager_handlers() {
538
  $items = array();
539
  // Delegate.
540
  foreach (panelizer_get_plugins_with_hook('default_page_manager_handlers') as $handler) {
541
    $handler->hook_default_page_manager_handlers($items);
542
  }
543

    
544
  return $items;
545
}
546

    
547
/**
548
 * Implement CTools access form caching callback: get.
549
 */
550
function panelizer_ctools_access_get($argument) {
551
  list($entity_type, $bundle, $name) = explode(':', $argument);
552
  $handler = panelizer_entity_plugin_get_handler($entity_type);
553
  $panelizer = $handler->get_default_panelizer_object($bundle, $name);
554

    
555
  if (empty($panelizer)) {
556
    return;
557
  }
558

    
559
  if (!$handler->access_default_panelizer_object($panelizer)) {
560
    return;
561
  }
562

    
563
  // First, see if there's a cache.
564
  ctools_include('object-cache');
565
  $access = ctools_object_cache_get('panelizer_access', $argument);
566
  if (!$access) {
567
    $access = $panelizer->access;
568
  }
569

    
570
  $context = $handler->get_contexts($panelizer);
571

    
572
  return array($access, $context);
573
}
574

    
575
/**
576
 * Implement CTools access form caching callback: set.
577
 */
578
function panelizer_ctools_access_set($argument, $access) {
579
  list($entity_type, $bundle, $name) = explode(':', $argument);
580
  $handler = panelizer_entity_plugin_get_handler($entity_type);
581
  $panelizer = $handler->get_default_panelizer_object($bundle, $name);
582

    
583
  if (empty($panelizer)) {
584
    return;
585
  }
586

    
587
  if (!$handler->access_default_panelizer_object($panelizer)) {
588
    return;
589
  }
590

    
591
  ctools_include('object-cache');
592
  ctools_object_cache_set('panelizer_access', $argument, $access);
593
}
594

    
595
/**
596
 * Implement CTools access form caching callback: get.
597
 */
598
function panelizer_ctools_access_clear($argument) {
599
  list($entity_type, $bundle, $name) = explode(':', $argument);
600
  $handler = panelizer_entity_plugin_get_handler($entity_type);
601
  $panelizer = $handler->get_default_panelizer_object($bundle, $name);
602

    
603
  if (empty($panelizer)) {
604
    return;
605
  }
606

    
607
  if (!$handler->access_default_panelizer_object($panelizer)) {
608
    return;
609
  }
610

    
611
  ctools_include('object-cache');
612
  ctools_object_cache_clear('panelizer', $argument);
613
}
614

    
615
// -----------------------------------------------------------------------
616
// CTools entity plugin support code.
617

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

    
645
        // Build the custom settings of the view modes for this bundle.
646
        $view_mode_settings = field_view_mode_settings($entity_type, $bundle);
647
        foreach ($entity_info['view modes'] as $view_mode_name => $view_mode_info) {
648
          $plugin['view mode status'][$bundle][$view_mode_name] = !empty($view_mode_settings[$view_mode_name]['custom_settings']);
649
        }
650
      }
651
    }
652

    
653
    // Add our fake view modes.
654
    $plugin['view modes'] = array(
655
      'page_manager' => array(
656
        'label' => t('Full page override'),
657
      ),
658
      'default' => array(
659
        'label' => t('Default'),
660
      ),
661
    );
662

    
663
    if (!empty($entity_info['view modes'])) {
664
      foreach ($entity_info['view modes'] as $view_mode => $view_mode_info) {
665
        $plugin['view modes'][$view_mode] = $view_mode_info;
666
      }
667
    }
668

    
669
    // It seems silly to unset this after but the logic is cleaner to read.
670
    if (empty($plugin['uses page manager'])) {
671
      unset($plugin['view modes']['page_manager']);
672
    }
673
  }
674

    
675
  drupal_alter('panelizer_entity_plugin_process', $plugin, $info);
676
}
677

    
678
/**
679
 * Fetch a single entity plugin.
680
 */
681
function panelizer_get_entity_plugin($entity_type) {
682
  ctools_include('plugins');
683
  return ctools_get_plugins('panelizer', 'entity', $entity_type);
684
}
685

    
686
/**
687
 * Fetch all entity plugin.
688
 */
689
function panelizer_get_entity_plugins() {
690
  ctools_include('plugins');
691
  return ctools_get_plugins('panelizer', 'entity');
692
}
693

    
694
/**
695
 * Get the class to handle custom code for a given entity type plugin.
696
 *
697
 * If a plugin does not define a class at all, then the default class.
698
 *
699
 * @return
700
 *   Either the instantiated handler or FALSE if one could not be had.
701
 */
702
function panelizer_entity_plugin_get_handler($plugin) {
703
  // The default plugin handler is abstract and cannot be loaded.
704
  if ($plugin == 'default') {
705
    return;
706
  }
707

    
708
  $cache = &drupal_static(__FUNCTION__, array());
709

    
710
  // If a string was passed, turn it into a plugin.
711
  if (is_string($plugin)) {
712
    $plugin = panelizer_get_entity_plugin($plugin);
713
    if (!$plugin) {
714
      return FALSE;
715
    }
716
  }
717

    
718
  // Get the class name from the 'handler' property if we have not already
719
  // cached a handler.
720
  if (empty($cache[$plugin['name']]) && ($class = ctools_plugin_get_class($plugin, 'handler'))) {
721
    // @todo is there a good reason to use ->init instead of __construct?
722
    $cache[$plugin['name']] = new $class();
723
    $cache[$plugin['name']]->init($plugin);
724
  }
725
  return !empty($cache[$plugin['name']]) ? $cache[$plugin['name']] : FALSE;
726
}
727

    
728
/**
729
 * Load handler to get a plugin as a menu callback.
730
 */
731
function panelizer_handler_load($entity_type) {
732
  return panelizer_entity_plugin_get_handler($entity_type);
733
}
734

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

    
755
  return $objects;
756
}
757

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

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

    
798
/**
799
 * Callback used for switching callbacks into the proper plugin.
800
 */
801
function panelizer_entity_plugin_callback_switcher($entity_type, $switcher_type, $op) {
802
  $args = func_get_args();
803
  if (count($args) < 3) {
804
    return FALSE;
805
  }
806
  $entity_type = array_shift($args);
807
  $switcher_type = array_shift($args);
808
  $op = array_shift($args);
809

    
810
  // Load the $plugin information.
811
  if ($handler = panelizer_entity_plugin_get_handler($entity_type)) {
812
    $method = $switcher_type . '_' . $op;
813
    if (method_exists($handler, $method)) {
814
      return call_user_func_array(array($handler, $method), $args);
815
    }
816
  }
817
  else {
818
    return FALSE;
819
  }
820
}
821

    
822
/**
823
 * Page callback to delegate to either the settings page or list page.
824
 */
825
function panelizer_default_list_or_settings_page($handler, $bundle, $name, $view_mode, $operation = 'list', $item = NULL) {
826
  if (is_string($handler)) {
827
    $handler = panelizer_entity_plugin_get_handler($handler);
828
  }
829

    
830
  // We need a version of $bundle with $view_mode but we need to retain one
831
  // without it so we can pass straight $bundle to the settings page.
832
  $test_bundle = $bundle;
833
  if ($view_mode) {
834
    $test_bundle .= '.' . $view_mode;
835
  }
836

    
837
  if ($handler->has_panel_choice($test_bundle)) {
838
    // Call through to the UI switcher for the list.
839
    ctools_include('export-ui');
840
    return panelizer_export_ui_switcher_page($handler, $test_bundle, 'panelizer_defaults', $operation, $item);
841
  }
842
  else {
843
    return panelizer_default_settings_page($handler, $bundle, $name, $view_mode);
844
  }
845
}
846

    
847
/**
848
 * Specialized version of ctools_export_ui_switcher_page().
849
 *
850
 * This one is designed to set our entity handler and bundle on the object so we
851
 * can refer to it later without having to override all of the entry points.
852
 */
853
function panelizer_export_ui_switcher_page($entity_handler, $bundle, $plugin_name, $op) {
854
  $args = func_get_args();
855

    
856
  // Remove the handler and the bundle.
857
  array_shift($args);
858
  array_shift($args);
859
  $js = !empty($_REQUEST['js']);
860

    
861
  // Break our bundle up as necessary.
862
  if (strpos($bundle, '.') !== FALSE) {
863
    list($bundle, $view_mode) = explode('.', $bundle);
864
  }
865
  else {
866
    $view_mode = 'page_manager';
867
  }
868

    
869
  // Load the $plugin information.
870
  ctools_include('export-ui');
871
  $plugin = ctools_get_export_ui($plugin_name);
872
  $handler = ctools_export_ui_get_handler($plugin);
873

    
874
  if ($handler) {
875
    if (is_string($entity_handler)) {
876
      $entity_handler = panelizer_entity_plugin_get_handler($entity_handler);
877
    }
878

    
879
    $handler->entity_handler = $entity_handler;
880
    $handler->entity_bundle = $bundle;
881
    $handler->entity_view_mode = $view_mode;
882

    
883
    if (empty($entity_handler->entity_admin_root) || substr($_GET['q'], 30) == 'admin/structure/panelizer') {
884
      $handler->plugin['menu']['menu prefix'] = 'admin/structure/panelizer' . $entity_handler->entity_type;
885
      $handler->plugin['menu']['menu item'] = $bundle;
886
    }
887
    else {
888
      $base_path = $entity_handler->entity_admin_root . '/panelizer/' . $view_mode;
889
      if (is_numeric($entity_handler->entity_admin_bundle)) {
890
        $bits = explode('/', $base_path);
891
        $bits[$entity_handler->entity_admin_bundle] = $bundle;
892
        $base_path = implode('/', $bits);
893
      }
894
      $handler->plugin['menu']['menu prefix'] = dirname($base_path);
895
      $handler->plugin['menu']['menu item'] = basename($base_path);
896
      foreach ($handler->plugin['menu']['items'] as $key => &$item) {
897
        $item['path'] = str_replace('list/', '', $item['path']);
898
      }
899
    }
900

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

    
903
    foreach ($handler->plugin['redirect'] as $key => $old_path) {
904
      if ($key == 'add') {
905
        $handler->plugin['redirect'][$key] = $path . '/%ctools_export_ui/settings';
906
      }
907
      else {
908
        $handler->plugin['redirect'][$key] = $path;
909
      }
910
    }
911

    
912
    $method = $op . '_page';
913
    if (method_exists($handler, $method)) {
914
      // Replace the first two arguments.
915
      $args[0] = $js;
916
      $args[1] = $_POST;
917
      return call_user_func_array(array($handler, $method), $args);
918
    }
919
  }
920
  else {
921
    return t('Configuration error. No handler found.');
922
  }
923
}
924

    
925
// ---------------------------------------------------------------------------
926
// Menu callbacks
927

    
928
/**
929
 * Title callback to properly set the tile when editing panelizer defaults.
930
 */
931
function panelizer_default_title_callback($handler, $bundle) {
932
  if (is_string($handler)) {
933
    $handler = panelizer_entity_plugin_get_handler($handler);
934
  }
935

    
936
  if (!$handler) {
937
    return '';
938
  }
939

    
940
  $entity_info = entity_get_info($handler->entity_type);
941

    
942
  $title = $entity_info['label'];
943

    
944
  if (strpos($bundle, '.') === FALSE) {
945
    $bundle = $bundle;
946
    $view_mode = '';
947
  }
948
  else {
949
    list($bundle, $view_mode) = explode('.', $bundle);
950
  }
951

    
952
  $title .= ' | ' . $handler->get_bundle_title($bundle);
953

    
954
  if ($view_mode && !empty($handler->plugin['view modes'][$view_mode]['label'])) {
955
    $title .= ' | ' . $handler->plugin['view modes'][$view_mode]['label'];
956
  }
957

    
958
  return $title;
959
}
960

    
961
/**
962
 * Menu callback to determine if a type has a choice of defaults.
963
 *
964
 * We use this to make sure the right tabs appear.
965
 */
966
function panelizer_has_choice_callback($handler, $bundle, $name = NULL) {
967
  if (is_string($handler)) {
968
    $handler = panelizer_entity_plugin_get_handler($handler);
969
  }
970

    
971
  if (empty($handler)) {
972
    return FALSE;
973
  }
974

    
975
  if (!panelizer_administer_entity_bundle($handler, $bundle)) {
976
    return FALSE;
977
  }
978

    
979
  // Check to see if $name is valid.
980
  if (!empty($name) && !$handler->get_default_panelizer_object($bundle, $name)) {
981
    return FALSE;
982
  }
983

    
984
  return $handler->has_panel_choice($bundle);
985
}
986

    
987
/**
988
 * Menu callback to determine if a type+view_mode has a choice of defaults.
989
 */
990
function panelizer_has_choice_callback_view_mode($handler, $bundle, $view_mode) {
991
  return panelizer_has_choice_callback($handler, $bundle . '.' . $view_mode);
992
}
993

    
994
/**
995
 * Menu callback to determine if a type has a choice of defaults.
996
 *
997
 * Use to make sure the right tabs appear.
998
 */
999
function panelizer_has_no_choice_callback($handler, $bundle, $view_mode = NULL) {
1000
  if (is_string($handler)) {
1001
    $handler = panelizer_entity_plugin_get_handler($handler);
1002
  }
1003

    
1004
  if (empty($handler)) {
1005
    return FALSE;
1006
  }
1007

    
1008
  if (!empty($view_mode)) {
1009
    $bundle .= '.' . $view_mode;
1010
  }
1011

    
1012
  if (!panelizer_administer_entity_bundle($handler, $bundle)) {
1013
    return FALSE;
1014
  }
1015

    
1016
  return !$handler->has_panel_choice($bundle);
1017
}
1018

    
1019
/**
1020
 * Menu callback to determine if a type has a choice of defaults.
1021
 *
1022
 * Used to make sure the right tabs appear.
1023
 */
1024
function panelizer_is_panelized($handler, $bundle, $view_mode = NULL) {
1025
  if (is_string($handler)) {
1026
    $handler = panelizer_entity_plugin_get_handler($handler);
1027
  }
1028

    
1029
  if (!$handler) {
1030
    return FALSE;
1031
  }
1032

    
1033
  if ($view_mode) {
1034
    $bundle .= '.' . $view_mode;
1035
  }
1036

    
1037
  if (!panelizer_administer_entity_bundle($handler, $bundle)) {
1038
    return FALSE;
1039
  }
1040

    
1041
  return $handler->is_panelized($bundle);
1042
}
1043

    
1044
/**
1045
 * Access callback to see if a user can administer a particular bundle.
1046
 */
1047
function panelizer_administer_entity_bundle($handler, $bundle) {
1048
  if (is_string($handler)) {
1049
    $handler = panelizer_entity_plugin_get_handler($handler);
1050
  }
1051

    
1052
  // Adjust for the presence of a view mode.
1053
  if (strpos($bundle, '.') !== FALSE) {
1054
    list($bundle, $view_mode) = explode('.', $bundle);
1055
  }
1056

    
1057
  return user_access('administer panelizer') || user_access("administer panelizer $handler->entity_type $bundle defaults");
1058
}
1059

    
1060
/**
1061
 * Access callback to see if a user can administer a particular default.
1062
 */
1063
function panelizer_administer_panelizer_default($handler, $bundle, $name, $view_mode = NULL) {
1064
  if (is_string($handler)) {
1065
    $handler = panelizer_entity_plugin_get_handler($handler);
1066
  }
1067

    
1068
  if ($view_mode) {
1069
    $bundle .= '.' . $view_mode;
1070
  }
1071

    
1072
  $panelizer = $handler->get_default_panelizer_object($bundle, $name);
1073
  if (!$panelizer) {
1074
    return FALSE;
1075
  }
1076

    
1077
  return $handler->access_default_panelizer_object($panelizer);
1078
}
1079

    
1080
/**
1081
 * Menu load callback to scrub a node bundle from the URL safe equivalent.
1082
 */
1083
function panelizer_node_type_load($name) {
1084
  if ($type = node_type_get_type(strtr($name, array('-' => '_')))) {
1085
    return $type->type;
1086
  }
1087
}
1088

    
1089
// ---------------------------------------------------------------------------
1090
// export.inc callbacks to handle proper in/out of our defaults.
1091

    
1092
/**
1093
 * export.inc callback to properly save a panelizer default.
1094
 */
1095
function panelizer_export_save_callback(&$object) {
1096
  if (!empty($object->display)) {
1097
    $object->display->storage_id = $object->name;
1098
    // First write the display.
1099
    panels_save_display($object->display);
1100

    
1101
    // Make sure we have the did.
1102
    $object->did = $object->display->did;
1103
  }
1104

    
1105
  // Then write the default
1106
  if ($object->export_type & EXPORT_IN_DATABASE) {
1107
    // Existing record.
1108
    $update = array('pnid');
1109
  }
1110
  else {
1111
    // New record.
1112
    $update = array();
1113
    $object->export_type = EXPORT_IN_DATABASE;
1114
  }
1115

    
1116
  // Reset the entity's cache. If the EntityCache module is enabled, this also
1117
  // resets its permanent cache.
1118
  list($entity_type, ) = explode(':', $object->name);
1119
  entity_get_controller($entity_type)->resetCache();
1120

    
1121
  return drupal_write_record('panelizer_defaults', $object, $update);
1122
}
1123

    
1124
/**
1125
 * export.inc callback to properly export a panelizer default.
1126
 */
1127
function panelizer_export_export_callback($object, $indent) {
1128
  $object->did = NULL;
1129
  $output = ctools_export_object('panelizer_defaults', $object, $indent);
1130
  $output .= panels_export_display($object->display, $indent);
1131
  $output .= $indent . '$panelizer->display = $display;' . "\n";
1132

    
1133
  return $output;
1134
}
1135

    
1136
/**
1137
 * export.inc callback to properly delete a panelizer default.
1138
 */
1139
function panelizer_export_delete_callback($object) {
1140
  if (!empty($object->did)) {
1141
    panels_delete_display($object->did);
1142
  }
1143

    
1144
  // Allow modules to react on a default Panelizer object before deletion.
1145
  // Triggers hook_panelizer_delete_default().
1146
  module_invoke_all('panelizer_delete_default', $object);
1147

    
1148
  db_delete('panelizer_defaults')
1149
    ->condition('name', $object->name)
1150
    ->execute();
1151
}
1152

    
1153
/**
1154
 * export.inc callback to delete sub records for an object.
1155
 */
1156
function panelizer_export_delete_callback_subrecords($objects) {
1157
  $dids = array();
1158
  foreach ($objects as $panelizer) {
1159
    if (!empty($panelizer->did)) {
1160
      $dids[$panelizer->did] = $panelizer->did;
1161
    }
1162
  }
1163

    
1164
  if ($dids) {
1165
    $displays = panels_load_displays($dids);
1166
    foreach ($objects as $panelizer) {
1167
      if (!empty($panelizer->did) && !empty($displays[$panelizer->did])) {
1168
        $panelizer->display = $displays[$panelizer->did];
1169
      }
1170
    }
1171
  }
1172
}
1173

    
1174
// ---------------------------------------------------------------------------
1175
// Context cache callbacks -- this really needs a less lame system someday.
1176

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

    
1196
  if ($entity_type == 'default') {
1197
    list($entity_type, $bundle, $name) = @explode(':', $key, 3);
1198
    $get_default = TRUE;
1199
  }
1200

    
1201
  if ($handler = panelizer_entity_plugin_get_handler($entity_type)) {
1202
    if (!empty($get_default)) {
1203
      $panelizer = $handler->get_default_panelizer_object($bundle, $name);
1204
      $panelizer->base_contexts = $handler->get_base_contexts();
1205
      return $panelizer;
1206
    }
1207
    else {
1208
      list($entity_id, $view_mode) = explode('.', $key);
1209
      $entities = entity_load($entity_type, array($entity_id));
1210
      if (!empty($entities[$entity_id]) && !empty($entities[$entity_id]->panelizer[$view_mode])) {
1211
        $panelizer = $entities[$entity_id]->panelizer[$view_mode];
1212
        $panelizer->base_contexts = $handler->get_base_contexts($entities[$entity_id]);
1213
        return $panelizer;
1214
      }
1215
    }
1216
  }
1217
}
1218

    
1219
/**
1220
 * Store the panelizer object in the object cache.
1221
 *
1222
 * CTools clumsy context editing system requires caching. This lets us do it
1223
 * reasonably.
1224
 *
1225
 * @param $entity_type
1226
 *   Can be something like 'node' or 'user' or 'default'.
1227
 * @param $key
1228
 *   Either the node type or the nid.
1229
 * @param $object
1230
 *   The cached object.
1231
 */
1232
function panelizer_context_cache_set($entity_type, $key, $object) {
1233
  ctools_include('object-cache');
1234
  ctools_object_cache_set('panelizer_context_cache', $entity_type . ':' . $key, $object);
1235
}
1236

    
1237
/**
1238
 * Clear the panelizer object in the object cache.
1239
 *
1240
 * CTools clumsy context editing system requires caching. This lets us do it
1241
 * reasonably.
1242
 *
1243
 * @param $entity_type
1244
 *   Can be something like 'node' or 'user' or 'default'.
1245
 * @param $key
1246
 *   Either the node type or the nid.
1247
 */
1248
function panelizer_context_cache_clear($entity_type, $key) {
1249
  ctools_include('object-cache');
1250
  ctools_object_cache_clear('panelizer_context_cache', $entity_type . ':' . $key);
1251
}
1252

    
1253
// --------------------------------------------------------------------------
1254
// Panels edit cache contexts.
1255

    
1256
/**
1257
 * Implements hook_panels_cache_get().
1258
 *
1259
 * Get display edit cache for a display being edited.
1260
 *
1261
 * The key is the second half of the key in this form: panelizer:TYPE:KEY
1262
 */
1263
function panelizer_panels_cache_get($argument) {
1264
  ctools_include('object-cache');
1265
  list($entity_type, $key) = explode(':', $argument, 2);
1266
  $cache = ctools_object_cache_get('panelizer_display_cache', $entity_type . ':' . $key);
1267

    
1268
  // Keep $type because $entity_type can be 'default' which is not actually an
1269
  // entity type in that case.
1270
  $type = $entity_type;
1271
  if ($entity_type == 'default') {
1272
    list($entity_type, $bundle, $name) = @explode(':', $key, 3);
1273
    $get_default = TRUE;
1274
  }
1275

    
1276
  $handler = panelizer_entity_plugin_get_handler($entity_type);
1277
  if (!$handler) {
1278
    return;
1279
  }
1280

    
1281
  // Extract the entity ID and view mode.
1282
  list($entity_id, $view_mode) = explode(':', $key, 2);
1283
  // If this entity supports revisions, and a custom revision is being
1284
  // displayed, it's possible for the key to also include the revision ID.
1285
  if ($handler->supports_revisions && strpos($view_mode, ':') !== FALSE) {
1286
    list($entity_id, $view_mode, $vid) = explode(':', $key);
1287
  }
1288

    
1289
  // If it's already cached, we still need to restore our contexts.
1290
  if (!empty($cache)) {
1291
    $cache->cached = TRUE;
1292
    if (!empty($get_default)) {
1293
      $panelizer = $handler->get_default_panelizer_object($bundle, $name);
1294
      $cache->display->context = $handler->get_contexts($panelizer);
1295

    
1296
      // Set the storage_type and storage_id if either is empty.
1297
      if (empty($cache->display->storage_type)) {
1298
        $cache->display->storage_type = 'panelizer_default';
1299
      }
1300
      if (empty($cache->display->storage_id)) {
1301
        $cache->display->storage_id = $panelizer->name;
1302
      }
1303
    }
1304
    else {
1305
      $conditions = (isset($vid) ? array('vid' => $vid) : array());
1306
      $entities = entity_load($entity_type, array($entity_id), $conditions);
1307
      if (!empty($entities[$entity_id]) && !empty($entities[$entity_id]->panelizer[$view_mode])) {
1308
        $panelizer = $entities[$entity_id]->panelizer[$view_mode];
1309
        $cache->display->context = $handler->get_contexts($panelizer, $entities[$entity_id]);
1310
      }
1311
    }
1312

    
1313
    return $cache;
1314
  }
1315

    
1316
  $cache = new stdClass();
1317

    
1318
  // If it wasn't cached, create a new cache.
1319
  if (!empty($get_default)) {
1320
    $panelizer = $handler->get_default_panelizer_object($bundle, $name);
1321
    $cache->display = $panelizer->display;
1322
    $cache->display->context = $handler->get_contexts($panelizer);
1323
    
1324
    // Set the storage_type and storage_id if either is empty.
1325
     if (empty($cache->display->storage_type)) {
1326
       $cache->display->storage_type = 'panelizer_default';
1327
     }
1328
     if (empty($cache->display->storage_id)) {
1329
       $cache->display->storage_id = $panelizer->name;
1330
     }
1331
  }
1332
  else {
1333
    $conditions = (isset($vid) ? array('vid' => $vid) : array());
1334
    $entities = entity_load($entity_type, array($entity_id), $conditions);
1335
    if (empty($entities[$entity_id]) || empty($entities[$entity_id]->panelizer[$view_mode])) {
1336
      return $cache;
1337
    }
1338

    
1339
    list($entity_id, $revision_id, $bundle) = entity_extract_ids($entity_type, $entities[$entity_id]);
1340
    $panelizer = $entities[$entity_id]->panelizer[$view_mode];
1341
    $cache->display = $panelizer->display;
1342
    $cache->display->context = $handler->get_contexts($panelizer, $entities[$entity_id]);
1343
  }
1344

    
1345
  ctools_include('common', 'panels');
1346
  ctools_include('plugins', 'panels');
1347

    
1348
  $cache_keys = array(
1349
    'panelizer',
1350
    $type,
1351
    $key,
1352
  );
1353
  if (isset($vid) && is_numeric($vid) && substr($key, strlen($vid) * -1) != $vid) {
1354
    $cache_keys[] = $vid;
1355
  }
1356
  $cache->display->cache_key = implode(':', $cache_keys);
1357

    
1358
  // Set the allowed content types.
1359
  if (variable_get('panelizer_' . $type . ':' . $bundle . '_allowed_types_default', FALSE)) {
1360
    $cache->content_types = panels_common_get_allowed_types('panels_page', $cache->display->context);
1361
  }
1362
  else {
1363
    $cache->content_types = panels_common_get_allowed_types('panelizer_' . $type . ':' . $bundle, $cache->display->context);
1364
  }
1365

    
1366
  // Set the allowed layout options.
1367
  $cache->display->allowed_layouts = panels_common_get_allowed_layouts(panelizer_get_allowed_layouts_option($type, $bundle));
1368

    
1369
  return $cache;
1370
}
1371

    
1372
/**
1373
 * Implements hook_panels_cache_set().
1374
 *
1375
 * Store a display edit in progress in the page cache.
1376
 */
1377
function panelizer_panels_cache_set($argument, $cache) {
1378
  ctools_include('object-cache');
1379
  ctools_object_cache_set('panelizer_display_cache', $argument, $cache);
1380
}
1381

    
1382
/**
1383
 * Implements hook_panels_cache_clear().
1384
 *
1385
 * Save all changes made to a display using the Page Manager page cache.
1386
 */
1387
function panelizer_panels_cache_clear($argument, $cache) {
1388
  ctools_include('object-cache');
1389
  ctools_object_cache_clear('panelizer_display_cache', $argument);
1390
}
1391

    
1392
/**
1393
 * Implements hook_panels_cache_save().
1394
 *
1395
 * Save all changes made to a display using the Page Manager page cache.
1396
 */
1397
function panelizer_panels_cache_save($argument, $cache) {
1398
  // If this is set, they clicked a button that saves a different panelizer
1399
  // than was being edited, such as saving to default rather than customizing
1400
  // an entity.
1401
  $original = $argument;
1402
  if (isset($cache->display->swap_cache_key)) {
1403
    $argument = $cache->display->swap_cache_key;
1404
  }
1405

    
1406
  list($entity_type, $key) = explode(':', $argument, 2);
1407
  $type = $entity_type;
1408
  if ($entity_type == 'default') {
1409
    list($entity_type, $bundle, $name) = @explode(':', $key, 3);
1410
    $get_default = TRUE;
1411
  }
1412

    
1413
  $handler = panelizer_entity_plugin_get_handler($entity_type);
1414
  if (!$handler) {
1415
    return;
1416
  }
1417

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

    
1441
// ---------------------------------------------------------------------------
1442
// Contrib module hooks to provide needed functionality.
1443

    
1444
/**
1445
 * Implements hook_export_node_alter().
1446
 *
1447
 * Integrate with export.module for saving panel_nodes into code.
1448
 */
1449
function panelizer_export_node_alter(&$node, $original_node, $method) {
1450
  // @todo
1451
}
1452

    
1453
/**
1454
 * Implements hook_panelizer_defaults_alter().
1455
 *
1456
 * Remove the panels node because there is no point to panelizing it.
1457
 */
1458
function panelizer_panelizer_default_types_alter(&$bundles, $entity_type) {
1459
  switch ($entity_type) {
1460
    case 'node':
1461
      // Disallow the panel node type, since it's already a panel.
1462
      if (module_exists('panels_node') && !empty($bundles['panel'])) {
1463
        unset($bundles['panel']);
1464
      }
1465
      break;
1466
  }
1467
}
1468

    
1469
/**
1470
 * Implements hook_features_pipe_panelizer_defaults_alter().
1471
 */
1472
function panelizer_features_pipe_panelizer_defaults_alter(&$more, $data, $export) {
1473
  foreach ($data as $machine_name) {
1474
    list ($entity_type, $bundle) = explode(':', $machine_name);
1475

    
1476
    $variables = array(
1477
      'panelizer_defaults_' . $entity_type . '_' . $bundle,
1478
      'panelizer_' . $entity_type . ':' . $bundle . '_allowed_layouts',
1479
      'panelizer_' . $entity_type . ':' . $bundle . '_allowed_layouts_default',
1480
      'panelizer_' . $entity_type . ':' . $bundle . '_allowed_types',
1481
      'panelizer_' . $entity_type . ':' . $bundle . '_allowed_types_default',
1482
      'panelizer_' . $entity_type . ':' . $bundle . '_default',
1483
    );
1484

    
1485
    // Add default display variables for each view mode.
1486
    $entity_info = entity_get_info($entity_type);
1487
    $default_base = 'panelizer_' . $entity_type . ':' . $bundle . ':';
1488
    foreach ($entity_info['view modes'] as $view_mode => $view_info) {
1489
      $variables[] = $default_base . $view_mode . '_selection';
1490
    }
1491
    $variables[] = $default_base . 'page_manager' . '_selection';
1492
    $variables[] = $default_base . 'default' . '_selection';
1493

    
1494
    foreach ($variables as $variable) {
1495
      $more['variable'][$variable] = $variable;
1496
    }
1497
  }
1498

    
1499
  return $more;
1500
}
1501

    
1502
/**
1503
 * Implements hook_search_api_alter_callback_info().
1504
 */
1505
function panelizer_search_api_alter_callback_info() {
1506
  $info = array();
1507
  $info['panelizer'] = array(
1508
    'name' => t('Panelizer'),
1509
    'description' => t('Add the content from the Panelizer "Full page override" to the search index.'),
1510
    'class' => 'PanelizerSearchApiAlterCallback',
1511
  );
1512
  return $info;
1513
}
1514

    
1515
// -----------------------------------------------------------------------
1516
// Theme functions where necessary.
1517

    
1518
/**
1519
 * Panelizer view mode theme function.
1520
 */
1521
function template_preprocess_panelizer_view_mode(&$vars) {
1522
  $element = $vars['element'];
1523
  $entity = $element['#panelizer_entity'];
1524
  $panelizer = $element['#panelizer'];
1525
  $handler = $element['#panelizer_handler'];
1526
  $info = $element['#panelizer_content'];
1527

    
1528
  $handler->preprocess_panelizer_view_mode($vars, $entity, $element, $panelizer, $info);
1529
}
1530

    
1531
// -----------------------------------------------------------------------
1532
// Drupal actions integration for VBO.
1533

    
1534
/**
1535
 * Implements hook_action_info().
1536
 */
1537
function panelizer_action_info() {
1538
  return array(
1539
    'panelizer_set_status_action' => array(
1540
      'type' => 'entity',
1541
      'label' => t('Set panelizer status'),
1542
      'vbo_configurable' => TRUE,
1543
      'configurable' => FALSE,
1544
      'behavior' => array('changes_property'),
1545
      'configurable' => TRUE,
1546
    )
1547
  );
1548
}
1549

    
1550
/**
1551
 * Executes the panelizer_set_status action.
1552
 */
1553
function panelizer_set_status_action($entity, $context) {
1554
  $view_mode = 'page_manager';
1555
  if (isset($context['view_mode'])) {
1556
    $view_mode = $context['view_mode'];
1557
  }
1558

    
1559
  list($entity_id, $revision_id, $bundle) = entity_extract_ids($context['entity_type'], $entity);
1560
  if (isset($context['panelizer_default'])) {
1561
    $entity->panelizer[$view_mode] = $context['panelizer_default'];
1562
    $entity->panelizer[$view_mode]->did = NULL;
1563

    
1564
    // Ensure original values are maintained.
1565
    $entity->panelizer[$view_mode]->entity_id = $entity_id;
1566
    $entity->panelizer[$view_mode]->revision_id = $revision_id;
1567
  }
1568
  else {
1569
    $entity->panelizer[$view_mode]->name = NULL;
1570
    $entity->panelizer[$view_mode]->did = NULL;
1571
  }
1572
}
1573

    
1574
/**
1575
 * Provides the panelizer_set_status_action form.
1576
 */
1577
function panelizer_set_status_action_form($context, &$form_state) {
1578
  $form = array();
1579
  $entity_info = entity_get_info($context['entity_type']);
1580
  $entities = entity_load($context['entity_type'], $form_state['selection']);
1581
  $bundles = array();
1582

    
1583
  $handler = panelizer_entity_plugin_get_handler($context['entity_type']);
1584
  // Collect our list of bundles.
1585
  foreach ($entities as $entity) {
1586
    list($entity_id, $revision_id, $bundle) = entity_extract_ids($context['entity_type'], $entity);
1587
    $bundles[$bundle] = $bundle;
1588
  }
1589

    
1590
  $conditions = array(
1591
    'panelizer_type' => $context['entity_type'],
1592
    'panelizer_key' => $bundles,
1593
  );
1594

    
1595
  ctools_include('export');
1596
  $defaults = ctools_export_load_object('panelizer_defaults', 'conditions', $conditions);
1597

    
1598
  foreach ($defaults as $name => $default) {
1599
    if (empty($default->title)) {
1600
      $default->title = t('Default');
1601
    }
1602
    $options[$default->view_mode][$name] = t('@bundle: @title', array('@bundle' => $entity_info['bundles'][$default->panelizer_key]['label'], '@title' => $default->title));
1603
  }
1604

    
1605
  $view_modes = array();
1606
  foreach ($handler->plugin['view modes'] as $view_mode => $view_mode_info) {
1607
    $view_modes[$view_mode] = $view_mode_info['label'];
1608
  }
1609

    
1610
  $form['panelizer']['#tree'] = TRUE;
1611

    
1612
  foreach ($view_modes as $view_mode => $label) {
1613
    if (empty($options[$view_mode])) {
1614
      unset($view_modes[$view_mode]);
1615
      continue;
1616
    }
1617

    
1618
    natcasesort($options[$view_mode]);
1619
    $panelizers = array(
1620
      'not' => t('Not panelized'),
1621
    ) + $options[$view_mode];
1622

    
1623
    $form['panelizer'][$view_mode] = array(
1624
      '#type' => 'select',
1625
      '#title' => t('Panelizer status'),
1626
      '#options' => $panelizers,
1627
      '#states' => array(
1628
        'visible' => array(
1629
          '#panelizer-view-mode' => array('value' => $view_mode),
1630
        ),
1631
      ),
1632
    );
1633
  }
1634

    
1635
  $form['view_mode'] = array(
1636
    '#type' => 'select',
1637
    '#title' => t('View mode'),
1638
    '#options' => $view_modes,
1639
    '#id' => 'panelizer-view-mode',
1640
    '#weight' => -10,
1641
  );
1642

    
1643
  $form['#panelizer_defaults'] = $defaults;
1644
  return $form;
1645
}
1646

    
1647
/**
1648
 * FormAPI submission callback.
1649
 */
1650
function panelizer_set_status_action_submit($form, $form_state) {
1651
  $view_mode = $form_state['values']['view_mode'];
1652
  $panelizer = $form_state['values']['panelizer'][$view_mode];
1653

    
1654
  $retval = array(
1655
    'panelizer' => $panelizer,
1656
    'view_mode' => $view_mode,
1657
  );
1658

    
1659
  if ($form_state['values']['panelizer'] != 'not') {
1660
    $retval['panelizer_default'] = $form['#panelizer_defaults'][$panelizer];
1661
  }
1662

    
1663
  return $retval;
1664
}
1665

    
1666
// --------------------------------------------------------------------------
1667
// Miscellaneous helper functions
1668

    
1669
/**
1670
 * Return list of operations.
1671
 *
1672
 * @see hook_panelizer_operations_alter().
1673
 */
1674
function panelizer_operations() {
1675
  $operations = array(
1676
    'settings' => array(
1677
      'menu title' => 'Settings',
1678
      'link title' => t('settings'),
1679
      'admin callback' => 'panelizer_default_settings_page',
1680
      // ctools export ui thinks this is 'edit'.
1681
      'ui path' => 'edit',
1682
    ),
1683
    'context' => array(
1684
      'menu title' => 'Context',
1685
      'link title' => t('context'),
1686
      'admin callback' => 'panelizer_default_context_page',
1687
    ),
1688
    'layout' => array(
1689
      'menu title' => 'Layout',
1690
      'link title' => t('layout'),
1691
      'admin callback' => 'panelizer_default_layout_page',
1692
    ),
1693
    'content' => array(
1694
      'menu title' => 'Content',
1695
      'link title' => t('content'),
1696
      'admin callback' => 'panelizer_default_content_page',
1697
    ),
1698
  );
1699

    
1700
  drupal_alter('panelizer_operations', $operations);
1701

    
1702
  return $operations;
1703
}
1704

    
1705
/**
1706
 * Gets the current layout options approach for an entity bundle.
1707
 *
1708
 * @param string $type
1709
 *   The entity type.
1710
 * @param string $bundle
1711
 *   The entity bundle.
1712
 *
1713
 * @return string
1714
 *   The name of the layout approach to check (default or per bundle).
1715
 */
1716
function panelizer_get_allowed_layouts_option($type, $bundle) {
1717
  if (variable_get('panelizer_' . $type . ':' . $bundle . '_allowed_layouts_default', FALSE)) {
1718
    return 'panels_page';
1719
  }
1720
  else {
1721
    return 'panelizer_' . $type . ':' . $bundle;
1722
  }
1723
}
1724

    
1725
/**
1726
 * Implements hook_form_FORM_ID_alter() for panels_ipe_edit_control_form().
1727
 *
1728
 * Alter the IPE save control form to handle extra Panelizer functionality.
1729
 */
1730
function panelizer_form_panels_ipe_edit_control_form_alter(&$form, &$form_state) {
1731
  if (empty($form_state['renderer'])) {
1732
    return;
1733
  }
1734

    
1735
  $renderer = $form_state['renderer'];
1736

    
1737
  $cache_key = $renderer->display->cache_key;
1738
  $parts = explode(':', $cache_key, 3);
1739
  if ($parts[0] != 'panelizer') {
1740
    return;
1741
  }
1742

    
1743
  list($module, $type, $key) = $parts;
1744

    
1745
  if ($type == 'default') {
1746
    return;
1747
  }
1748

    
1749
  // Load the $plugin information.
1750
  $handler = panelizer_entity_plugin_get_handler($type);
1751
  if (!$handler) {
1752
    return;
1753
  }
1754

    
1755
  // Get the entity that's being edited.
1756
  list($entity_id, $view_mode) = explode(':', $key);
1757
  $entities = entity_load($handler->entity_type, array($entity_id));
1758
  if (empty($entities[$entity_id])) {
1759
    return;
1760
  }
1761

    
1762
  $entity = $entities[$entity_id];
1763
  list($entity_id, $revision_id, $bundle) = entity_extract_ids($handler->entity_type, $entity);
1764
  $entity_info = entity_get_info($handler->entity_type);
1765

    
1766
  if (empty($entity->panelizer[$view_mode])) {
1767
    return;
1768
  }
1769

    
1770
  $panelizer = $entities[$entity_id]->panelizer[$view_mode];
1771

    
1772
  module_load_include('inc', 'panelizer', 'includes/common');
1773
  $revision_info = $handler->entity_allows_revisions($entity);
1774

    
1775
  // Set panelizer info regardless of revision or panelizer layout default
1776
  // status.
1777
  $form_state['panelizer entity'] = $entity;
1778
  $form_state['panelizer bundle'] = $bundle;
1779
  $form_state['panelizer handler'] = $handler;
1780
  $form_state['panelizer view_mode'] = $view_mode;
1781

    
1782
  // If this entity has revisions enabled we can assume that they have
1783
  // permissions to add revisions via IPE.
1784
  if (!empty($revision_info)) {
1785
    $form_state['entity'] = $entity;
1786
    $form_state['revision info'] = $revision_info;
1787
    panelizer_add_revision_info_form($form, $form_state);
1788
    // Tweak the log message field to make it fit better.
1789
    if (isset($form['revision_information']['log'])) {
1790
      $form['revision_information']['log']['#type'] = 'textfield';
1791
      $form['revision_information']['log']['#description'] = '';
1792
    }
1793
  }
1794

    
1795
  // If the entity already has customized panelizer data, add the revert button.
1796
  if (!empty($panelizer->did)) {
1797
    if ($handler->has_default_panel($bundle . '.' . $view_mode)) {
1798
      $uri = entity_uri($handler->entity_type, $entity);
1799
      $url = $uri['path'];
1800
      // Support for Workbench Moderation to redirect to the newest revision for
1801
      // this node.
1802
      if ($handler->entity_type == 'node' && module_exists('workbench_moderation')) {
1803
        $url = 'node/' . $entity->nid . '/current-revision';
1804
      }
1805
      $redirect_url = url($uri['path'] . '/panelizer/' . $view_mode . '/reset', array('query' => array('destination' => $url)));
1806
      drupal_add_js(array('panelizer' => array('revert_default_url' => $redirect_url)), 'setting');
1807

    
1808
      $form['buttons']['revert_default'] = array(
1809
        '#type' => 'submit',
1810
        '#value' => t('Revert to @bundle_name default', array('@bundle_name' => $entity_info['bundles'][$bundle]['label'])),
1811
        '#submit' => array('panels_ipe_revert_to_default'),
1812
        '#attributes' => array('class' => array('panels-ipe-cancel')),
1813
        '#id' => 'panelizer-ipe-revert',
1814
        '#access' => $handler->panelizer_access('defaults', $entity, $panelizer->view_mode),
1815
      );
1816
    }
1817
    return;
1818
  }
1819

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

    
1823
  // Calculate the proper name to add to the cache key, which has some data
1824
  // stripped off of the true name.
1825
  $name = 'default';
1826
  if (!empty($panelizer->name)) {
1827
    $pieces = explode(':', $panelizer->name);
1828
    if (isset($pieces[2])) {
1829
      $name = $pieces[2];
1830
    }
1831
  }
1832

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

    
1849
/**
1850
 * Implements hook_form_FORM_ID_alter() for panels_change_layout().
1851
 *
1852
 * Alter the change layout form to support saving as default.
1853
 */
1854
function panelizer_form_panels_change_layout_alter(&$form, &$form_state) {
1855
  // Only alter on initial form build.
1856
  if (empty($form_state['executed'])) {
1857
    if (isset($form_state['back'])) {
1858
      // Do nothing when moving backwards.
1859
      return;
1860
    }
1861

    
1862
    // Extract the display from the form state.
1863
    $display = $form_state['display'];
1864

    
1865
    $cache_key = $display->cache_key;
1866
    $parts = explode(':', $cache_key, 3);
1867
    if ($parts[0] != 'panelizer') {
1868
      return;
1869
    }
1870

    
1871
    list($module, $type, $key) = $parts;
1872

    
1873
    // If the display is not owned by Panelizer, or is default handler, exit.
1874
    if ($module != 'panelizer' || $type == 'default') {
1875
      return;
1876
    }
1877

    
1878
    // Load the $plugin information.
1879
    $handler = panelizer_entity_plugin_get_handler($type);
1880
    if (!$handler) {
1881
      return;
1882
    }
1883

    
1884
    // Get the entity that's being edited through Panelizer context.
1885
    $entity = $display->context['panelizer']->data;
1886

    
1887
    // Check if the view mode is configured.
1888
    list($entity_id, $view_mode) = explode(':', $key);
1889
    if (empty($entity->panelizer[$view_mode])) {
1890
      return;
1891
    }
1892

    
1893
    list($entity_id, $revision_id, $bundle) = entity_extract_ids($handler->entity_type, $entity);
1894
    $entity_info = entity_get_info($handler->entity_type);
1895

    
1896
    $panelizer = $entity->panelizer[$view_mode];
1897

    
1898
    // Calculate the proper name to add to the cache key, which has some data
1899
    // stripped off of the true name.
1900
    $name = 'default';
1901
    if (!empty($panelizer->name)) {
1902
      $pieces = explode(':', $panelizer->name);
1903
      if (isset($pieces[2])) {
1904
        $name = $pieces[2];
1905
      }
1906
    }
1907

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

    
1911
    // Add another button to save as the default instead.
1912
    $form['save_default'] = array(
1913
      '#type' => 'submit',
1914
      '#value' => t('Save as @bundle_name default', array('@bundle_name' => $entity_info['bundles'][$bundle]['label'])),
1915
      '#submit' => array('panels_ipe_change_to_default', 'panels_change_layout_submit'),
1916
      '#save-display' => TRUE,
1917
      '#cache_key' => 'default:' . $handler->entity_type . ':' . $bundle . '.' . $panelizer->view_mode . ':' . $name,
1918
      '#access' => $handler->panelizer_access('defaults', $entity, $panelizer->view_mode),
1919
    );
1920
  }
1921
}
1922

    
1923
/**
1924
 * Implement template_preprocess_panels_ipe_toolbar().
1925
 */
1926
function panelizer_preprocess_panels_ipe_toolbar(&$variables) {
1927
  // Some custom CSS to improve the UX.
1928
  // $variables['#attached'] = array(
1929
  //   'css' => array(
1930
  //     drupal_get_path('module', 'panelizer') . '/css/panelizer.ipe.css',
1931
  //   ),
1932
  // );
1933
  // dpm($variables);
1934
}
1935

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

    
1956
/**
1957
 * Submit handler to save the panelizer default instead of customizing the
1958
 * entity.
1959
 */
1960
function panels_ipe_change_to_default($form, &$form_state) {
1961
  // Change the cache key so that it saves to the default instead of the
1962
  // entity. This works because we're actually editing the original display
1963
  // anyway, and everything else keys off the cache key.
1964
  $form_state['display']->swap_cache_key = $form_state['triggering_element']['#cache_key'];
1965
}
1966

    
1967
/**
1968
 * Submit handler to revert to the default panelizer.
1969
 */
1970
function panels_ipe_revert_to_default($form, &$form_state) {
1971
  // Reduce code complexity due to indirection.
1972
  $handler = $form_state['panelizer handler'];
1973
  $entity = $form_state['panelizer entity'];
1974
  $bundle = $form_state['panelizer bundle'];
1975
  $view_mode = $form_state['panelizer view_mode'];
1976
  $renderer = $form_state['renderer'];
1977

    
1978
  $handler->delete_entity_panelizer($entity, $view_mode);
1979

    
1980
  $name = implode(':', array($handler->entity_type, $bundle, 'default'));
1981
  if ($view_mode != 'page_manager') {
1982
    $name .= ':' . $view_mode;
1983
  }
1984
  $cache_key = $form_state['display']->cache_key;
1985

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

    
1989
  $renderer->display = $display = $panelizer->display;
1990
  $display->cache_key = $cache_key;
1991

    
1992
  $display->context = $handler->get_contexts($panelizer, $entity);
1993

    
1994
  $renderer->commands[] = ajax_command_replace("#panels-ipe-display-{$renderer->clean_key}", panels_render_display($display, $renderer));
1995
}
1996

    
1997
/**
1998
 * Implements hook_panelizer_pre_render_alter().
1999
 *
2000
 * Panelizer fails to communicate to the theme layer what view mode an entity's
2001
 * fields are being rendered in, so we unfortunately have to do that ourselves.
2002
 */
2003
function panelizer_panelizer_pre_render_alter(&$panelizer, &$display, &$entity) {
2004
  foreach ($entity->panelizer as $view_mode => $reference_panelizer) {
2005
    if ($reference_panelizer === $panelizer) {
2006
      $entity->panelizer_view_mode = $view_mode;
2007
      break;
2008
    }
2009
  }
2010
}
2011

    
2012
/**
2013
 * Implements hook_workbench_moderation_node_history_view_alter().
2014
 *
2015
 * This is a little kludgy as the data in the row is stored as final HTML for
2016
 * display.
2017
 */
2018
function panelizer_workbench_moderation_node_history_view_alter(&$rows) {
2019
  // Load the node.
2020
  $node = node_load(arg(1));
2021

    
2022
  // Verify the user has access to the Panelizer configuration.
2023
  if (panelizer_is_panelized('node', $node->type)) {
2024
    // Loop over each table row.
2025
    foreach ($rows as $key => &$row) {
2026
      // Published.
2027
      $path = 'node/' . $node->nid . '/panelizer';
2028

    
2029
      // Not published.
2030
      if (!in_array('published-revision', $row['class'])) {
2031
        $path = 'node/' . $node->nid . '/revisions/' . $row['data']['vid'] . '/panelizer';
2032
      }
2033

    
2034
      // Add a link to the Panelizer page.
2035
      $row['data']['revision'] .= ' | ' . l('Customize display', $path);
2036
    }
2037
  }
2038
}
2039

    
2040
/**
2041
 * Menu callback load method to either return the requested revision ID or FALSE
2042
 * to prevent the tab from being processed.
2043
 *
2044
 * @param string $vid
2045
 *   An entity's revision ID.
2046
 *
2047
 * @return mixed
2048
 *   Either the revision_id or FALSE if the revision was empty.
2049
 */
2050
function panelizer_node_revision_load($revision_id = NULL) {
2051
  if (!empty($revision_id)) {
2052
    return $revision_id;
2053
  }
2054
  return FALSE;
2055
}
2056

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

    
2078
              // Clean the some basic settings.
2079
              $fpp->fpid = NULL;
2080
              $fpp->created = NULL;
2081
              $fpp->timestamp = NULL;
2082

    
2083
              // Save the cloned FPP.
2084
              $newfpp = fieldable_panels_panes_save($fpp);
2085

    
2086
              // Update the FPP reference.
2087
              $pane->subtype = 'fpid:' . $newfpp->fpid;
2088
            }
2089
          }
2090
        }
2091
      }
2092
    }
2093
  }
2094
}