Projet

Général

Profil

Paste
Télécharger (48,7 ko) Statistiques
| Branche: | Révision:

root / drupal7 / sites / all / modules / panelizer / panelizer.module @ 87dbc3bf

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

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

    
11
// -----------------------------------------------------------------------
12
// Drupal core hooks
13

    
14
/**
15
 * Implements hook_permission().
16
 */
17
function panelizer_permission() {
18
  $items = array(
19
    'administer panelizer' => array(
20
      'title' => t('administer panelizer'),
21
      'description' => t('Fully administer panelizer and all panelizer settings.'),
22
    ),
23
  );
24

    
25
  // Delegate.
26
  foreach (panelizer_get_plugins_with_hook('permission') as $handler) {
27
    $handler->hook_permission($items);
28
  }
29

    
30
  return $items;
31
}
32

    
33
/**
34
 * Implements hook_theme().
35
 */
36
function panelizer_theme() {
37
  $items = array();
38

    
39
  $items['panelizer_settings_page_table'] = array(
40
    'render element' => 'element',
41
    'file' => 'includes/admin.inc',
42
  );
43

    
44
  $items['panelizer_view_mode'] = array(
45
    'render element' => 'element',
46
    'template' => 'panelizer-view-mode',
47
    'path' => drupal_get_path('module', 'panelizer') . '/templates',
48
  );
49

    
50
  // Delegate.
51
  foreach (panelizer_get_plugins_with_hook('theme') as $handler) {
52
    $handler->hook_theme($items);
53
  }
54

    
55
  return $items;
56
}
57

    
58
/**
59
 * Implements hook_menu().
60
 */
61
function panelizer_menu() {
62
  $items = array();
63

    
64
  // Delegate admin menu stuff to admin.inc
65
  ctools_include('admin', 'panelizer');
66
  panelizer_admin_hook_menu($items);
67

    
68
  // Delegate.
69
  foreach (panelizer_get_plugins_with_hook('menu') as $handler) {
70
    $handler->hook_menu($items);
71
  }
72

    
73
  return $items;
74
}
75

    
76
/**
77
 * Implements hook_menu_alter().
78
 */
79
function panelizer_menu_alter(&$items) {
80
  // Delegate.
81
  foreach (panelizer_get_plugins_with_hook('menu_alter') as $handler) {
82
    $handler->hook_menu_alter($items);
83
  }
84
}
85

    
86
/**
87
 * Implements hook_admin_paths().
88
 */
89
function panelizer_admin_paths() {
90
  $items = array();
91

    
92
  // Delegate.
93
  foreach (panelizer_get_plugins_with_hook('admin_paths') as $handler) {
94
    $handler->hook_admin_paths($items);
95
  }
96

    
97
  return $items;
98
}
99

    
100
/**
101
 * Implements hook_form_alter().
102
 */
103
function panelizer_form_alter(&$form, &$form_state, $form_id) {
104
  // Delegate.
105
  foreach (panelizer_get_plugins_with_hook('form_alter') as $handler) {
106
    $handler->hook_form_alter($form, $form_state, $form_id);
107

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

    
112
        // Provide settings for the default content and layout options
113
        $form['default_settings'] = array(
114
          '#type' => 'fieldset',
115
          '#title' => t('Default settings'),
116
          '#group' => 'additional_settings',
117
          '#weight' => -20,
118
        );
119
        $form['default_settings']['default_content_settings'] = array(
120
          '#title' => t('Use the same allowed content as standard Panels pages?'),
121
          '#type' => 'checkbox',
122
          '#default_value' => variable_get($form_state['build_info']['args'][0] . '_allowed_types_default', FALSE),
123
        );
124
        $form['default_settings']['default_layout_settings'] = array(
125
          '#title' => t('Use the same allowed  layouts as standard Panels pages?'),
126
          '#type' => 'checkbox',
127
          '#default_value' => variable_get($form_state['build_info']['args'][0] . '_allowed_layouts_default', FALSE),
128
        );
129

    
130
        // Disable the layout options when the default layout setting is enabled
131
        if (!empty($form['layout_selection']['layouts']) && variable_get($form_state['build_info']['args'][0] . '_allowed_layouts_default', FALSE)) {
132
          $form['layout_selection']['layouts']['#disabled'] = TRUE;
133
        }
134

    
135
        // Disable the content options when the default content setting is enabled
136
        if (variable_get($form_state['build_info']['args'][0] . '_allowed_types_default', FALSE)) {
137
          $content_types = ctools_content_get_all_types();
138
          $content_types['other'] = array('title' => t('Other'), 'weight' => 10);
139
          foreach($content_types as $content_type => $content_type_value) {
140
            if (!empty($form['content_types'][$content_type]['options'])) {
141
              $form['content_types'][$content_type]['options']['#disabled'] = TRUE;
142
            }
143
          }
144
          $form['common']['panels_common_default']['#disabled'] = TRUE;
145
        }
146

    
147
        $form['#submit'][] = 'panelizer_panels_default_settings_submit';
148
      }
149
    }
150
  }
151
}
152

    
153
/**
154
 * Custom submission handler for setting default content and layout settings
155
 */
156
function panelizer_panels_default_settings_submit($form, &$form_state) {
157
  variable_set($form_state['values']['module_name'] . '_allowed_types_default', $form_state['values']['default_content_settings']);
158
  variable_set($form_state['values']['module_name'] . '_allowed_layouts_default', $form_state['values']['default_layout_settings']);
159
}
160

    
161
/**
162
 * Implements hook_page_alter().
163
 */
164
function panelizer_page_alter(&$page) {
165
  // Delegate.
166
  foreach (panelizer_get_plugins_with_hook('page_alter') as $handler) {
167
    $handler->hook_page_alter($page);
168
  }
169
}
170

    
171
/**
172
 * Implements hook_entity_load().
173
 */
174
function panelizer_entity_load(&$entities, $entity_type) {
175
  // Delegate to the handler.
176
  if ($handler = panelizer_entity_plugin_get_handler($entity_type)) {
177
    $handler->hook_entity_load($entities);
178
  }
179
}
180

    
181
/**
182
 * Implements hook_entity_update().
183
 */
184
function panelizer_entity_update($entity, $entity_type) {
185
  // Delegate to the handler.
186
  if ($handler = panelizer_entity_plugin_get_handler($entity_type)) {
187
    $handler->hook_entity_update($entity);
188
  }
189
}
190

    
191
/**
192
 * Implements hook_entity_insert().
193
 */
194
function panelizer_entity_insert($entity, $entity_type) {
195
  // Delegate to the handler.
196
  if ($handler = panelizer_entity_plugin_get_handler($entity_type)) {
197
    $handler->hook_entity_insert($entity);
198
  }
199
}
200

    
201
/**
202
 * Implements hook_entity_delete().
203
 */
204
function panelizer_entity_delete($entity, $entity_type) {
205
  // Delegate to the handler.
206
  if ($handler = panelizer_entity_plugin_get_handler($entity_type)) {
207
    $handler->hook_entity_delete($entity);
208
  }
209
}
210

    
211
/**
212
 * Implements hook_field_attach_delete_revision().
213
 */
214
function panelizer_field_attach_delete_revision($entity_type, $entity) {
215
  // Delegate to the handler.
216
  if ($handler = panelizer_entity_plugin_get_handler($entity_type)) {
217
    $handler->hook_field_attach_delete_revision($entity);
218
  }
219
}
220

    
221
function panelizer_field_attach_form($entity_type, $entity, &$form, &$form_state, $langcode) {
222
  // Delegate to the handler.
223
  if ($handler = panelizer_entity_plugin_get_handler($entity_type)) {
224
    $handler->hook_field_attach_form($entity, $form, $form_state, $langcode);
225
  }
226
}
227

    
228
function panelizer_field_attach_submit($entity_type, $entity, &$form, &$form_state) {
229
  // Delegate to the handler.
230
  if ($handler = panelizer_entity_plugin_get_handler($entity_type)) {
231
    $handler->hook_field_attach_submit($entity, $form, $form_state);
232
  }
233
}
234

    
235
/**
236
 * Implements hook_entity_view_alter().
237
 */
238
function panelizer_entity_view_alter(&$build, $entity_type) {
239
  static $recursion_prevention = array();
240
  // Prepare variables.
241
  $handler = panelizer_entity_plugin_get_handler($entity_type);
242
  if (!$handler) {
243
    return;
244
  }
245

    
246
  $entity = $handler->get_entity_view_entity($build);
247

    
248
  // Safety check in case we can't find the entity.
249
  if (!$entity) {
250
    return;
251
  }
252

    
253
  list($entity_id, $revision_id, $bundle) = entity_extract_ids($entity_type, $entity);
254

    
255
  // If the requested view mode does not exist, rendering will fall back
256
  // to 'default' and we should check that one instead.
257
  $view_mode = $build['#view_mode'];
258

    
259
  // Test to see if this view mode is actually panelizable at all.
260
  if (!isset($handler->plugin['view modes'][$view_mode]) || (empty($handler->plugin['view modes'][$view_mode]['custom settings']) && empty($handler->plugin['view mode status'][$bundle][$view_mode]))) {
261
    $view_mode = 'default';
262
  }
263

    
264
  // Make sure the bundle + view mode is actually panelized!
265
  if (!$handler->is_panelized($bundle . '.' . $view_mode)) {
266
    return;
267
  }
268

    
269
  if (!empty($recursion_prevention[$entity_type][$entity_id][$view_mode])) {
270
    return;
271
  }
272

    
273
  $recursion_prevention[$entity_type][$entity_id][$view_mode] = TRUE;
274

    
275
  if ($info = $handler->render_entity($entity, $view_mode)) {
276
    // Change theming function and add the content on the $build array.
277
    $build['#theme'] = 'panelizer_view_mode';
278
    $build['#panelizer'] = $entity->panelizer[$view_mode];
279
    $build['#panelizer_content'] = $info;
280
    $build['#panelizer_handler'] = $handler;
281
    $build['#panelizer_entity'] = $entity;
282
    $build['#panelizer_bundle'] = $bundle;
283
    $build['#panelizer_entity_id'] = $entity_id;
284
  }
285
  $recursion_prevention[$entity_type][$entity_id][$view_mode] = FALSE;
286

    
287
}
288

    
289
// -----------------------------------------------------------------------
290
// Panels and CTools hooks
291

    
292
/**
293
 * Implements hook_ctools_plugin_type()
294
 */
295
function panelizer_ctools_plugin_type() {
296
  $items['entity'] = array(
297
    'cache' => FALSE,
298
    'process' => array(
299
      'function' => 'panelizer_entity_plugin_process',
300
    ),
301
    'classes' => array('handler'),
302
  );
303

    
304
  return $items;
305
}
306

    
307
/**
308
 * Implements hook_ctools_plugin_directory()
309
 */
310
function panelizer_ctools_plugin_directory($module, $plugin) {
311
  if (in_array($module, array('panelizer', 'ctools', 'page_manager'))) {
312
    return 'plugins/' . $plugin;
313
  }
314
}
315

    
316
/**
317
 * Implements hook_ctools_plugin_api().
318
 */
319
function panelizer_ctools_plugin_api($module, $api) {
320
  if (($module == 'page_manager' && $api == 'pages_default') || $module == 'panelizer') {
321
    return array(
322
      'version' => 1,
323
      'path' => drupal_get_path('module', 'panelizer') . '/includes',
324
    );
325
  }
326
}
327

    
328
/**
329
 * Implements hook_features_api().
330
 */
331
function panelizer_features_api() {
332
  $api = array();
333
  if (function_exists('_ctools_features_get_info') && defined('FEATURES_ALTER_TYPE_NONE')) {
334
    $api['panelizer_defaults'] = _ctools_features_get_info('panelizer_defaults');
335
    // CTools calls our hook_panelizer_defaults_alter so prevent Features from
336
    // calling it too. FEATURES_ALTER_TYPE_INLINE means we are handling alter
337
    // hooks ourselves here.
338
    $api['panelizer_defaults']['alter_type'] = FEATURES_ALTER_TYPE_INLINE;
339
    // Provide a separate alter hook for features_override.
340
    $api['panelizer_defaults']['alter_hook'] = 'panelizer_defaults_override';
341
  }
342

    
343
  return $api;
344
}
345

    
346
/**
347
 * Implementation of hook_views_api().
348
 */
349
function panelizer_views_api() {
350
  return array(
351
    'api' => 2.0,
352
    'path' => drupal_get_path('module', 'panelizer') . '/plugins/views',
353
  );
354
}
355

    
356
/**
357
 * Implements hook_panelizer_defaults_alter().
358
 */
359
function panelizer_panelizer_defaults_alter(&$items) {
360
  // Delegate.
361
  foreach (panelizer_get_plugins_with_hook('panelizer_defaults') as $handler) {
362
    $handler->hook_panelizer_defaults($items);
363
  }
364

    
365
  // Allow features_overrides to alter the config.
366
  drupal_alter('panelizer_defaults_override', $items);
367
}
368

    
369
/**
370
 * Implements hook_default_page_manager_handlers().
371
 */
372
function panelizer_default_page_manager_handlers() {
373
  $items = array();
374
  // Delegate.
375
  foreach (panelizer_get_plugins_with_hook('default_page_manager_handlers') as $handler) {
376
    $handler->hook_default_page_manager_handlers($items);
377
  }
378

    
379
  return $items;
380
}
381

    
382
/**
383
 * Implement CTools access form caching callback: get.
384
 */
385
function panelizer_ctools_access_get($argument) {
386
  list($entity_type, $bundle, $name) = explode(':', $argument);
387
  $handler = panelizer_entity_plugin_get_handler($entity_type);
388
  $panelizer = $handler->get_default_panelizer_object($bundle, $name);
389

    
390
  if (empty($panelizer)) {
391
    return;
392
  }
393

    
394
  if (!$handler->access_default_panelizer_object($panelizer)) {
395
    return;
396
  }
397

    
398
  // First, see if there's a cache
399
  ctools_include('object-cache');
400
  $access = ctools_object_cache_get('panelizer_access', $argument);
401
  if (!$access) {
402
    $access = $panelizer->access;
403
  }
404

    
405
  $context = $handler->get_contexts($panelizer);
406

    
407
  return array($access, $context);
408
}
409

    
410
/**
411
 * Implement CTools access form caching callback: set.
412
 */
413
function panelizer_ctools_access_set($argument, $access) {
414
  list($entity_type, $bundle, $name) = explode(':', $argument);
415
  $handler = panelizer_entity_plugin_get_handler($entity_type);
416
  $panelizer = $handler->get_default_panelizer_object($bundle, $name);
417

    
418
  if (empty($panelizer)) {
419
    return;
420
  }
421

    
422
  if (!$handler->access_default_panelizer_object($panelizer)) {
423
    return;
424
  }
425

    
426
  ctools_include('object-cache');
427
  ctools_object_cache_set('panelizer_access', $argument, $access);
428
}
429

    
430
/**
431
 * Implement CTools access form caching callback: get.
432
 */
433
function panelizer_ctools_access_clear($argument) {
434
  list($entity_type, $bundle, $name) = explode(':', $argument);
435
  $handler = panelizer_entity_plugin_get_handler($entity_type);
436
  $panelizer = $handler->get_default_panelizer_object($bundle, $name);
437

    
438
  if (empty($panelizer)) {
439
    return;
440
  }
441

    
442
  if (!$handler->access_default_panelizer_object($panelizer)) {
443
    return;
444
  }
445

    
446
  ctools_include('object-cache');
447
  ctools_object_cache_clear('panelizer', $argument);
448
}
449

    
450
// -----------------------------------------------------------------------
451
// CTools entity plugin support code
452

    
453
/**
454
 * CTools process callback for an entity plugin.
455
 *
456
 * This adds configuration data to the plugin so that we know what
457
 * bundles it is enabled for.
458
 */
459
function panelizer_entity_plugin_process(&$plugin, $info) {
460
  $entity_type = $plugin['name'];
461
  $entity_info = entity_get_info($entity_type);
462
  $plugin['bundles'] = array();
463
  if ($entity_info) {
464
    foreach ($entity_info['bundles'] as $bundle => $label) {
465
      if ($settings = variable_get('panelizer_defaults_' . $entity_type . '_' . $bundle, array())) {
466
        // Translate from settings that existed prior to view mode
467
        // support.
468
        if (empty($settings['view modes'])) {
469
          $old_settings = $settings;
470
          $settings = array('view modes' => array());
471
          if (empty($plugin['uses page manager'])) {
472
            $settings['view modes']['default'] = $old_settings;
473
          }
474
          else {
475
            $settings['view modes']['page_manager'] = $old_settings;
476
          }
477
          $settings['status'] = $old_settings['status'];
478
        }
479
        $plugin['bundles'][$bundle] = $settings;
480

    
481
        // Build the custom settings of the view modes for this bundle.
482
        $view_mode_settings = field_view_mode_settings($entity_type, $bundle);
483
        foreach ($entity_info['view modes'] as $view_mode_name => $view_mode_info) {
484
          $plugin['view mode status'][$bundle][$view_mode_name] = !empty($view_mode_settings[$view_mode_name]['custom_settings']);
485
        }
486
      }
487
    }
488

    
489
    // Add our fake view modes.
490
    $plugin['view modes'] = array(
491
      'page_manager' => array(
492
        'label' => t('Full page override'),
493
      ),
494
      'default' => array(
495
        'label' => t('Default'),
496
      ),
497
    );
498

    
499
    if (!empty($entity_info['view modes'])) {
500
      foreach ($entity_info['view modes'] as $view_mode => $view_mode_info) {
501
        $plugin['view modes'][$view_mode] = $view_mode_info;
502
      }
503
    }
504

    
505
    // It seems silly to unset this after but the logic is cleaner to read.
506
    if (empty($plugin['uses page manager'])) {
507
      unset($plugin['view modes']['page_manager']);
508
    }
509
  }
510

    
511
  drupal_alter('panelizer_entity_plugin_process', $plugin, $info);
512
}
513

    
514
/**
515
 * Fetch a single entity plugin.
516
 */
517
function panelizer_get_entity_plugin($entity_type) {
518
  ctools_include('plugins');
519
  return ctools_get_plugins('panelizer', 'entity', $entity_type);
520
}
521

    
522
/**
523
 * Fetch all entity plugin.
524
 */
525
function panelizer_get_entity_plugins() {
526
  ctools_include('plugins');
527
  return ctools_get_plugins('panelizer', 'entity');
528
}
529

    
530
/**
531
 * Get the class to handle custom code for a given entity type plugin.
532
 *
533
 * If a plugin does not define a class at all, then the default class
534
 *
535
 * @return
536
 *   Either the instantiated handler or FALSE if one could not be had.
537
 */
538
function panelizer_entity_plugin_get_handler($plugin) {
539
  // The default plugin handler is abstract and cannot be loaded.
540
  if ($plugin == 'default') {
541
    return;
542
  }
543

    
544
  $cache = &drupal_static(__FUNCTION__, array());
545

    
546
  // If a string was passed, turn it into a plugin.
547
  if (is_string($plugin)) {
548
    $plugin = panelizer_get_entity_plugin($plugin);
549
    if (!$plugin) {
550
      return FALSE;
551
    }
552
  }
553

    
554
  // Get the class name from the 'handler' property if we have not already
555
  // cached a handler.
556
  if (empty($cache[$plugin['name']]) && ($class = ctools_plugin_get_class($plugin, 'handler'))) {
557
    // @todo is there a good reason to use ->init instead of __construct?
558
    $cache[$plugin['name']] = new $class();
559
    $cache[$plugin['name']]->init($plugin);
560
  }
561
  return !empty($cache[$plugin['name']]) ? $cache[$plugin['name']] : FALSE;
562
}
563

    
564
/**
565
 * Load handler to get a plugin as a menu callback.
566
 */
567
function panelizer_handler_load($entity_type) {
568
  return panelizer_entity_plugin_get_handler($entity_type);
569
}
570

    
571
/**
572
 * Fetch handler objects for all plugins that implement the named hook.
573
 *
574
 * These plugins must set $plugin['hooks'][$hook] = TRUE in order to
575
 * be instantiated.
576
 *
577
 * This is only called for system wide hooks such as hook_menu and
578
 * hook_menu_alter; entity specific hooks will always be called.
579
 */
580
function panelizer_get_plugins_with_hook($hook) {
581
  $objects = array();
582
  $plugins = panelizer_get_entity_plugins();
583
  foreach ($plugins as $entity_type => $plugin) {
584
    if (!empty($plugin['hooks'][$hook])) {
585
      if ($handler = panelizer_entity_plugin_get_handler($plugin)) {
586
        $objects[$entity_type] = $handler;
587
      }
588
    }
589
  }
590

    
591
  return $objects;
592
}
593

    
594
/**
595
 * Page callback for entity menu callbacks.
596
 *
597
 * This function is to be used as a menu callback for menu items that
598
 * are to be handled by a method on the handler object. It loads the object
599
 * defined in the plugin and hands it off to a method based upon the name
600
 * of the operation in use.
601
 *
602
 * For example, if the 'op' is 'revision' then the callback method will be
603
 * 'page_revisions', with all of the arguments *except* the $op and the
604
 * plugin name.
605
 */
606
function panelizer_entity_plugin_switcher_page($entity_type, $op) {
607
  $args = func_get_args();
608
  $js = !empty($_REQUEST['js']);
609

    
610
  // Load the $plugin information
611
  if ($handler = panelizer_entity_plugin_get_handler($entity_type)) {
612
    // replace the first two arguments:
613
    $args[0] = $js;
614
    $args[1] = $_POST;
615
    $method = 'page_' . $op;
616
    if (method_exists($handler, $method)) {
617
      return call_user_func_array(array($handler, $method), $args);
618
    }
619
    // Check to see if this is an operation from panelizer_operations
620
    // with a callback instead.
621
    $operations = panelizer_operations();
622
    if (isset($operations[$op]) && isset($operations[$op]['entity callback']) && function_exists($operations[$op]['entity callback'])) {
623
      array_unshift($args, $handler);
624
      return call_user_func_array($operations[$op]['entity callback'], $args);
625
    }
626
  }
627
  else {
628
    return t('Configuration error. No handler found.');
629
  }
630
}
631

    
632
/**
633
 * Callback used for switching callbacks into the proper plugin.
634
 */
635
function panelizer_entity_plugin_callback_switcher($entity_type, $switcher_type, $op) {
636
  $args = func_get_args();
637
  if (count($args) < 3) {
638
    return FALSE;
639
  }
640
  $entity_type = array_shift($args);
641
  $switcher_type = array_shift($args);
642
  $op = array_shift($args);
643

    
644
  // Load the $plugin information
645
  if ($handler = panelizer_entity_plugin_get_handler($entity_type)) {
646
    $method = $switcher_type . '_' . $op;
647
    if (method_exists($handler, $method)) {
648
      return call_user_func_array(array($handler, $method), $args);
649
    }
650
  }
651
  else {
652
    return FALSE;
653
  }
654
}
655

    
656
/**
657
 * Page callback to delegate to either the settings page or list page.
658
 */
659
function panelizer_default_list_or_settings_page($handler, $bundle, $name, $view_mode, $operation = 'list', $item = NULL) {
660
  if (is_string($handler)) {
661
    $handler = panelizer_entity_plugin_get_handler($handler);
662
  }
663

    
664
  // We need a version of $bundle with $view_mode but we need to retain one
665
  // without it so we can pass straight $bundle to the settings page.
666
  $test_bundle = $bundle;
667
  if ($view_mode) {
668
    $test_bundle .= '.' . $view_mode;
669
  }
670

    
671
  if ($handler->has_panel_choice($test_bundle)) {
672
    // Call through to the UI switcher for the list
673
    ctools_include('export-ui');
674
    return panelizer_export_ui_switcher_page($handler, $test_bundle, 'panelizer_defaults', $operation, $item);
675
  }
676
  else {
677
    return panelizer_default_settings_page($handler, $bundle, $name, $view_mode);
678
  }
679
}
680

    
681
/**
682
 * Specialized version of ctools_export_ui_switcher_page()
683
 *
684
 * This one is designed to set our entity handler and bundle on the
685
 * object so we can refer to it later without having to override
686
 * all of the entry points.
687
 */
688
function panelizer_export_ui_switcher_page($entity_handler, $bundle, $plugin_name, $op) {
689
  $args = func_get_args();
690

    
691
  // Remove the handler and the bundle.
692
  array_shift($args);
693
  array_shift($args);
694
  $js = !empty($_REQUEST['js']);
695

    
696
  // Break our bundle up as necessary.
697
  if (strpos($bundle, '.') !== FALSE) {
698
    list($bundle, $view_mode) = explode('.', $bundle);
699
  }
700
  else {
701
    $view_mode = 'page_manager';
702
  }
703

    
704
  // Load the $plugin information
705
  $plugin = ctools_get_export_ui($plugin_name);
706
  $handler = ctools_export_ui_get_handler($plugin);
707

    
708
  if ($handler) {
709
    if (is_string($entity_handler)) {
710
      $entity_handler = panelizer_entity_plugin_get_handler($entity_handler);
711
    }
712

    
713
    $handler->entity_handler = $entity_handler;
714
    $handler->entity_bundle = $bundle;
715
    $handler->entity_view_mode = $view_mode;
716

    
717
    if (empty($entity_handler->entity_admin_root) || substr($_GET['q'], 30) == 'admin/config/content/panelizer') {
718
      $handler->plugin['menu']['menu prefix'] = 'admin/config/content/panelizer/' . $entity_handler->entity_type;
719
      $handler->plugin['menu']['menu item'] = $bundle;
720
    }
721
    else {
722
      $base_path = $entity_handler->entity_admin_root . '/panelizer/' . $view_mode;
723
      if (is_numeric($entity_handler->entity_admin_bundle)) {
724
        $bits = explode('/', $base_path);
725
        $bits[$entity_handler->entity_admin_bundle] = $bundle;
726
        $base_path = implode('/', $bits);
727
      }
728
      $handler->plugin['menu']['menu prefix'] = dirname($base_path);
729
      $handler->plugin['menu']['menu item'] = basename($base_path);
730
      foreach ($handler->plugin['menu']['items'] as $key => &$item) {
731
        $item['path'] = str_replace('list/', '', $item['path']);
732
      }
733
    }
734

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

    
737
    foreach ($handler->plugin['redirect'] as $key => $old_path) {
738
      if ($key == 'add') {
739
        $handler->plugin['redirect'][$key] = $path . '/list/%ctools_export_ui/settings';
740
      }
741
      else {
742
        $handler->plugin['redirect'][$key] = $path . '/list';
743
      }
744
    }
745

    
746
    $method = $op . '_page';
747
    if (method_exists($handler, $method)) {
748
      // replace the first two arguments:
749
      $args[0] = $js;
750
      $args[1] = $_POST;
751
      return call_user_func_array(array($handler, $method), $args);
752
    }
753
  }
754
  else {
755
    return t('Configuration error. No handler found.');
756
  }
757
}
758

    
759
// ---------------------------------------------------------------------------
760
// Menu callbacks
761

    
762
/**
763
 * Title callback to properly set the tile when editing panelizer defaults.
764
 */
765
function panelizer_default_title_callback($handler, $bundle) {
766
  if (is_string($handler)) {
767
    $handler = panelizer_entity_plugin_get_handler($handler);
768
  }
769

    
770
  if (!$handler) {
771
    return '';
772
  }
773

    
774
  $entity_info = entity_get_info($handler->entity_type);
775

    
776
  $title = $entity_info['label'];
777

    
778
  if (strpos($bundle, '.') === FALSE) {
779
    $bundle = $bundle;
780
    $view_mode = '';
781
  }
782
  else {
783
    list($bundle, $view_mode) = explode('.', $bundle);
784
  }
785

    
786
  $title .= ' | ' . $handler->get_bundle_title($bundle);
787

    
788
  if ($view_mode && !empty($handler->plugin['view modes'][$view_mode]['label'])) {
789
    $title .= ' | ' . $handler->plugin['view modes'][$view_mode]['label'];
790
  }
791

    
792
  return $title;
793
}
794

    
795
/**
796
 * Menu callback to determine if a type has a choice of defaults.
797
 *
798
 * We use this to make sure the right tabs appear.
799
 */
800
function panelizer_has_choice_callback($handler, $bundle, $name = NULL) {
801
  if (is_string($handler)) {
802
    $handler = panelizer_entity_plugin_get_handler($handler);
803
  }
804

    
805
  if (!$handler) {
806
    return FALSE;
807
  }
808

    
809
  if (!panelizer_administer_entity_bundle($handler, $bundle)) {
810
    return FALSE;
811
  }
812

    
813
  // Check to see if $name is valid
814
  if ($name && !$handler->get_default_panelizer_object($bundle, $name)) {
815
    return FALSE;
816
  }
817

    
818
  return $handler->has_panel_choice($bundle);
819
}
820

    
821
/**
822
 * Menu callback to determine if a type has a choice of defaults, with view mode.
823
 */
824
function panelizer_has_choice_callback_view_mode($handler, $bundle, $view_mode) {
825
  return panelizer_has_choice_callback($handler, $bundle . '.' . $view_mode);
826
}
827

    
828
/**
829
 * Menu callback to determine if a type has a choice of defaults.
830
 *
831
 * We use this to make sure the right tabs appear.
832
 */
833
function panelizer_has_no_choice_callback($handler, $bundle, $view_mode = NULL) {
834
  if (is_string($handler)) {
835
    $handler = panelizer_entity_plugin_get_handler($handler);
836
  }
837

    
838
  if (!$handler) {
839
    return FALSE;
840
  }
841

    
842
  if ($view_mode) {
843
    $bundle .= '.' . $view_mode;
844
  }
845

    
846
  if (!panelizer_administer_entity_bundle($handler, $bundle)) {
847
    return FALSE;
848
  }
849

    
850
  return $handler->has_default_panel($bundle) && !$handler->has_panel_choice($bundle);
851
}
852

    
853
/**
854
 * Menu callback to determine if a type has a choice of defaults.
855
 *
856
 * We use this to make sure the right tabs appear.
857
 */
858
function panelizer_is_panelized($handler, $bundle, $view_mode = NULL) {
859
  if (is_string($handler)) {
860
    $handler = panelizer_entity_plugin_get_handler($handler);
861
  }
862

    
863
  if (!$handler) {
864
    return FALSE;
865
  }
866

    
867
  if ($view_mode) {
868
    $bundle .= '.' . $view_mode;
869
  }
870

    
871
  if (!panelizer_administer_entity_bundle($handler, $bundle)) {
872
    return FALSE;
873
  }
874

    
875
  return $handler->is_panelized($bundle);
876
}
877

    
878
/**
879
 * Access callback to see if a user can administer a particular bundle.
880
 */
881
function panelizer_administer_entity_bundle($handler, $bundle) {
882
  if (is_string($handler)) {
883
    $handler = panelizer_entity_plugin_get_handler($handler);
884
  }
885

    
886
  // adjust for the presence of a view mode.
887
  if (strpos($bundle, '.') !== FALSE) {
888
    list($bundle, $view_mode) = explode('.', $bundle);
889
  }
890

    
891
  return user_access('administer panelizer') || user_access("administer panelizer $handler->entity_type $bundle defaults");
892
}
893

    
894
/**
895
 * Access callback to see if a user can administer a particular panelizer default.
896
 */
897
function panelizer_administer_panelizer_default($handler, $bundle, $name, $view_mode = NULL) {
898
  if (is_string($handler)) {
899
    $handler = panelizer_entity_plugin_get_handler($handler);
900
  }
901

    
902
  if ($view_mode) {
903
    $bundle .= '.' . $view_mode;
904
  }
905

    
906
  $panelizer = $handler->get_default_panelizer_object($bundle, $name);
907
  if (!$panelizer) {
908
    return FALSE;
909
  }
910

    
911
  return $handler->access_default_panelizer_object($panelizer);
912
}
913

    
914
/**
915
 * Menu load callback to scrub a node bundle from the URL safe equivalent.
916
 */
917
function panelizer_node_type_load($name) {
918
  if ($type = node_type_get_type(strtr($name, array('-' => '_')))) {
919
    return $type->type;
920
  }
921
}
922

    
923
// ---------------------------------------------------------------------------
924
// export.inc callbacks to handle proper in/out of our defaults
925

    
926
/**
927
 * export.inc callback to properly save a panelizer default.
928
 */
929
function panelizer_export_save_callback(&$object) {
930
  if (!empty($object->display)) {
931
    // First write the display
932
    panels_save_display($object->display);
933

    
934
    // Make sure we have the did.
935
    $object->did = $object->display->did;
936
  }
937

    
938
  // Then write the default
939
  if ($object->export_type & EXPORT_IN_DATABASE) {
940
    // Existing record.
941
    $update = array('pnid');
942
  }
943
  else {
944
    // New record.
945
    $update = array();
946
    $object->export_type = EXPORT_IN_DATABASE;
947
  }
948

    
949
  return drupal_write_record('panelizer_defaults', $object, $update);
950
}
951

    
952
/**
953
 * export.inc callback to properly export a panelizer default.
954
 */
955
function panelizer_export_export_callback($object, $indent) {
956
  $object->did = NULL;
957
  $output = ctools_export_object('panelizer_defaults', $object, $indent);
958
  $output .= panels_export_display($object->display, $indent);
959
  $output .= $indent . '$panelizer->display = $display;' . "\n";
960

    
961
  return $output;
962
}
963

    
964
/**
965
 * export.inc callback to properly delete a panelizer default.
966
 */
967
function panelizer_export_delete_callback($object) {
968
  if (!empty($object->did)) {
969
    panels_delete_display($object->did);
970
  }
971

    
972
  db_delete('panelizer_defaults')
973
    ->condition('name', $object->name)
974
    ->execute();
975
}
976

    
977
/**
978
 * export.inc callback to delete sub records for an object.
979
 */
980
function panelizer_export_delete_callback_subrecords($objects) {
981
  $dids = array();
982
  foreach ($objects as $panelizer) {
983
    if (!empty($panelizer->did)) {
984
      $dids[$panelizer->did] = $panelizer->did;
985
    }
986
  }
987

    
988
  if ($dids) {
989
    $displays = panels_load_displays($dids);
990
    foreach ($objects as $panelizer) {
991
      if (!empty($panelizer->did) && !empty($displays[$panelizer->did])) {
992
        $panelizer->display = $displays[$panelizer->did];
993
      }
994
    }
995
  }
996
}
997

    
998
// ---------------------------------------------------------------------------
999
// Context cache callbacks -- this really needs a less lame system someday.
1000

    
1001
/**
1002
 * Fetch the panelizer object from the object cache.
1003
 *
1004
 * CTools clumsy context editing system requires caching. This lets us
1005
 * do it reasonably.
1006
 *
1007
 * @param $entity_type
1008
 *   Can be something like 'node' or 'user' or 'default'.
1009
 * @param $key
1010
 *   Depends on the $entity_type. Can be a nid, a uid or a default key.
1011
 */
1012
function panelizer_context_cache_get($entity_type, $key) {
1013
  ctools_include('object-cache');
1014
  $cache = ctools_object_cache_get('panelizer_context_cache', $entity_type . ':' . $key);
1015
  if (!empty($cache)) {
1016
    $cache->cached = TRUE;
1017
    return $cache;
1018
  }
1019

    
1020
  if ($entity_type == 'default') {
1021
    list($entity_type, $bundle, $name) = @explode(':', $key, 3);
1022
    $get_default = TRUE;
1023
  }
1024

    
1025
  if ($handler = panelizer_entity_plugin_get_handler($entity_type)) {
1026
    if (!empty($get_default)) {
1027
      $panelizer = $handler->get_default_panelizer_object($bundle, $name);
1028
      $panelizer->base_contexts = $handler->get_base_contexts();
1029
      return $panelizer;
1030
    }
1031
    else {
1032
      list($entity_id, $view_mode) = explode('.', $key);
1033
      $entities = entity_load($entity_type, array($entity_id));
1034
      if (!empty($entities[$entity_id]) && !empty($entities[$entity_id]->panelizer[$view_mode])) {
1035
        $panelizer = $entities[$entity_id]->panelizer[$view_mode];
1036
        $panelizer->base_contexts = $handler->get_base_contexts($entities[$entity_id]);
1037
        return $panelizer;
1038
      }
1039
    }
1040
  }
1041
}
1042

    
1043
/**
1044
 * Store the panelizer object in the object cache.
1045
 *
1046
 * CTools clumsy context editing system requires caching. This lets us
1047
 * do it reasonably.
1048
 *
1049
 * @param $entity_type
1050
 *   Can be something like 'node' or 'user' or 'default'.
1051
 * @param $key
1052
 *   Either the node type or the nid.
1053
 * @param $object
1054
 *   The cached object.
1055
 */
1056
function panelizer_context_cache_set($entity_type, $key, $object) {
1057
  ctools_include('object-cache');
1058
  ctools_object_cache_set('panelizer_context_cache', $entity_type . ':' . $key, $object);
1059
}
1060

    
1061
/**
1062
 * Clear the panelizer object in the object cache.
1063
 *
1064
 * CTools clumsy context editing system requires caching. This lets us
1065
 * do it reasonably.
1066
 *
1067
 * @param $entity_type
1068
 *   Can be something like 'node' or 'user' or 'default'.
1069
 * @param $key
1070
 *   Either the node type or the nid.
1071
 */
1072
function panelizer_context_cache_clear($entity_type, $key) {
1073
  ctools_include('object-cache');
1074
  ctools_object_cache_clear('panelizer_context_cache', $entity_type . ':' . $key);
1075
}
1076

    
1077
// --------------------------------------------------------------------------
1078
// Panels edit cache contexts.
1079

    
1080
/**
1081
 * Get display edit cache for a panel being edited.
1082
 *
1083
 * The key is the second half of the key in this form:
1084
 * panelizer:TYPE:KEY;
1085
 */
1086
function panelizer_panels_cache_get($argument) {
1087
  ctools_include('object-cache');
1088
  list($entity_type, $key) = explode(':', $argument, 2);
1089
  $cache = ctools_object_cache_get('panelizer_display_cache', $entity_type . ':' . $key);
1090

    
1091
  // Keep $type because $entity_type can be 'default' which is not actually an
1092
  // entity type in that case.
1093
  $type = $entity_type;
1094
  if ($entity_type == 'default') {
1095
    list($entity_type, $bundle, $name) = @explode(':', $key, 3);
1096
    $get_default = TRUE;
1097
  }
1098

    
1099
  $handler = panelizer_entity_plugin_get_handler($entity_type);
1100
  if (!$handler) {
1101
    return;
1102
  }
1103

    
1104
  // If it's already cached, we still need to restore our contexts.
1105
  if (!empty($cache)) {
1106
    $cache->cached = TRUE;
1107
    if (!empty($get_default)) {
1108
      $panelizer = $handler->get_default_panelizer_object($bundle, $name);
1109
      $cache->display->context = $handler->get_contexts($panelizer);
1110
    }
1111
    else {
1112
      list($entity_id, $view_mode) = explode(':', $key);
1113
      $entities = entity_load($entity_type, array($entity_id));
1114
      if (!empty($entities[$entity_id]) && !empty($entities[$entity_id]->panelizer[$view_mode])) {
1115
        $panelizer = $entities[$entity_id]->panelizer[$view_mode];
1116
        $cache->display->context = $handler->get_contexts($panelizer, $entities[$entity_id]);
1117
      }
1118
    }
1119

    
1120
    return $cache;
1121
  }
1122

    
1123
  $cache = new stdClass();
1124

    
1125
  // If it wasn't cached, create a new cache.
1126
  if (!empty($get_default)) {
1127
    $panelizer = $handler->get_default_panelizer_object($bundle, $name);
1128
    $cache->display = $panelizer->display;
1129
    $cache->display->context = $handler->get_contexts($panelizer);
1130
  }
1131
  else {
1132
    list($entity_id, $view_mode) = explode(':', $key);
1133
    $entities = entity_load($entity_type, array($entity_id));
1134
    if (empty($entities[$entity_id]) || empty($entities[$entity_id]->panelizer[$view_mode])) {
1135
      return $cache;
1136
    }
1137

    
1138
    list($entity_id, $revision_id, $bundle) = entity_extract_ids($entity_type, $entities[$entity_id]);
1139
    $panelizer = $entities[$entity_id]->panelizer[$view_mode];
1140
    $cache->display = $panelizer->display;
1141
    $cache->display->context = $handler->get_contexts($panelizer, $entities[$entity_id]);
1142
  }
1143

    
1144
  ctools_include('common', 'panels');
1145
  ctools_include('plugins', 'panels');
1146
  $cache->display->cache_key = "panelizer:$type:$key";
1147

    
1148
  // Set the allowed content types
1149
  if (variable_get('panelizer_' . $type . ':' . $bundle . '_allowed_types_default', FALSE)) {
1150
    $cache->content_types = panels_common_get_allowed_types('panels_page', $cache->display->context);
1151
  }
1152
  else {
1153
    $cache->content_types = panels_common_get_allowed_types('panelizer_' . $type . ':' . $bundle, $cache->display->context);
1154
  }
1155

    
1156
  // Set the allowed layout options
1157
  if (variable_get('panelizer_' . $type . ':' . $bundle . '_allowed_layouts_default', FALSE)) {
1158
    $cache->display->allowed_layouts = panels_common_get_allowed_layouts('panels_page');
1159
  }
1160
  else {
1161
    $cache->display->allowed_layouts = panels_common_get_allowed_layouts('panelizer_' . $type . ':' . $bundle, $cache->display->context);
1162
  }
1163

    
1164
  return $cache;
1165
}
1166

    
1167
/**
1168
 * Store a display edit in progress in the page cache.
1169
 */
1170
function panelizer_panels_cache_set($argument, $cache) {
1171
  list($type, $key) = explode(':', $argument, 2);
1172
  ctools_include('object-cache');
1173
  ctools_object_cache_set('panelizer_display_cache', $type . ':' . $key, $cache);
1174
}
1175

    
1176
/**
1177
 * Save all changes made to a display using the Page Manager page cache.
1178
 */
1179
function panelizer_panels_cache_clear($argument, $cache) {
1180
  list($type, $key) = explode(':', $argument, 2);
1181
  ctools_include('object-cache');
1182
  ctools_object_cache_clear('panelizer_display_cache', $type . ':' . $key);
1183
}
1184

    
1185
/**
1186
 * Save all changes made to a display using the Page Manager page cache.
1187
 */
1188
function panelizer_panels_cache_save($argument, $cache) {
1189
  // If this is set, they clicked a button that saves a different panelizer
1190
  // than was being edited, such as saving to default rather than customizing
1191
  // an entity.
1192
  $original = $argument;
1193
  if (isset($cache->display->swap_cache_key)) {
1194
    $argument = $cache->display->swap_cache_key;
1195
  }
1196

    
1197
  list($entity_type, $key) = explode(':', $argument, 2);
1198
  $type = $entity_type;
1199
  if ($entity_type == 'default') {
1200
    list($entity_type, $bundle, $name) = @explode(':', $key, 3);
1201
    $get_default = TRUE;
1202
  }
1203

    
1204
  $handler = panelizer_entity_plugin_get_handler($entity_type);
1205
  if (!$handler) {
1206
    return;
1207
  }
1208

    
1209
  if (!empty($get_default)) {
1210
    $panelizer = $handler->get_default_panelizer_object($bundle, $name);
1211
    $panelizer->display = $cache->display;
1212
    ctools_include('export');
1213
    ctools_export_crud_save('panelizer_defaults', $panelizer);
1214
  }
1215
  else {
1216
    list($entity_id, $view_mode) = explode(':', $key);
1217
    $entities = entity_load($entity_type, array($entity_id));
1218
    if ($entities[$entity_id] && $entities[$entity_id]->panelizer[$view_mode]) {
1219
      $entities[$entity_id]->panelizer[$view_mode]->display = $cache->display;
1220
      $entities[$entity_id]->panelizer[$view_mode]->display_is_modified = TRUE;
1221
      $handler->entity_save($entities[$entity_id]);
1222
      // The display may have been cloned in the save process, so we need
1223
      // to be sure to put the old display back, and its contexts.
1224
      $cache->display = $entities[$entity_id]->panelizer[$view_mode]->display;
1225
      $cache->display->context = $handler->get_contexts($entities[$entity_id]->panelizer[$view_mode], $entities[$entity_id]);
1226
    }
1227
  }
1228
  panelizer_panels_cache_clear($original, $cache);
1229
}
1230

    
1231
// ---------------------------------------------------------------------------
1232
// Contrib module hooks to provide needed functionality.
1233

    
1234
/**
1235
 * Implements hook_export_node_alter().
1236
 *
1237
 * Integrate with export.module for saving panel_nodes into code.
1238
 */
1239
function panelizer_export_node_alter(&$node, $original_node, $method) {
1240
  // @todo
1241
}
1242

    
1243
/**
1244
 * Implements hook_panelizer_defaults_alter().
1245
 *
1246
 * Remove the panels node because there is no point to panelizing it.
1247
 */
1248
function panelizer_panelizer_default_types_alter(&$bundles, $entity_type) {
1249
  switch ($entity_type) {
1250
    case 'node':
1251
      // Disallow the panel node type, since it's already a panel.
1252
      if (module_exists('panels_node') && !empty($bundles['panel'])) {
1253
        unset($bundles['panel']);
1254
      }
1255
      break;
1256
  }
1257
}
1258

    
1259
/**
1260
 * Implements hook_features_export_alter().
1261
 */
1262
function panelizer_features_export_alter(&$export, $module_name) {
1263
  if (!empty($export['features']['panelizer_defaults'])) {
1264
    foreach ($export['features']['panelizer_defaults'] as $machine_name) {
1265
      list ($entity_type, $bundle) = explode(':', $machine_name);
1266

    
1267
      $variables = array(
1268
        'panelizer_defaults_' . $entity_type . '_' . $bundle,
1269
        'panelizer_' . $entity_type . ':' . $bundle . '_allowed_layouts',
1270
        'panelizer_' . $entity_type . ':' . $bundle . '_allowed_types',
1271
        'panelizer_' . $entity_type . ':' . $bundle . '_default'
1272
      );
1273

    
1274
      if (module_exists('strongarm')) {
1275
        foreach ($variables as $key => $variable) {
1276
          if (variable_get($variable) === NULL) {
1277
            unset($variables[$key]);
1278
          }
1279
        }
1280
        $variables = array_diff($variables, array_keys(strongarm_vars_load()));
1281
      }
1282

    
1283
      foreach ($variables as $variable) {
1284
        $export['features']['variable'][$variable] = $variable;
1285
      }
1286
    }
1287
  }
1288

    
1289
  return array();
1290
}
1291

    
1292
// -----------------------------------------------------------------------
1293
// Theme functions where necessary.
1294

    
1295
/**
1296
 * Panelizer view mode theme function.
1297
 */
1298
function template_preprocess_panelizer_view_mode(&$vars) {
1299
  $element = $vars['element'];
1300
  $entity = $element['#panelizer_entity'];
1301
  $panelizer = $element['#panelizer'];
1302
  $handler = $element['#panelizer_handler'];
1303
  $info = $element['#panelizer_content'];
1304

    
1305
  $handler->preprocess_panelizer_view_mode($vars, $entity, $element, $panelizer, $info);
1306
}
1307

    
1308
// -----------------------------------------------------------------------
1309
// Drupal actions integration for VBO.
1310

    
1311
/**
1312
 * Implements hook_action_info().
1313
 */
1314
function panelizer_action_info() {
1315
  return array(
1316
    'panelizer_set_status_action' => array(
1317
      'type' => 'entity',
1318
      'label' => t('Set panelizer status'),
1319
      'vbo_configurable' => TRUE,
1320
      'configurable' => FALSE,
1321
      'behavior' => array('changes_property'),
1322
      'configurable' => TRUE,
1323
    )
1324
  );
1325
}
1326

    
1327
/**
1328
 * Executes the panelizer_set_status action.
1329
 */
1330
function panelizer_set_status_action($entity, $context) {
1331
  $view_mode = 'page_manager';
1332
  if (isset($context['view_mode'])) {
1333
    $view_mode = $context['view_mode'];
1334
  }
1335

    
1336
  list($entity_id, $revision_id, $bundle) = entity_extract_ids($context['entity_type'], $entity);
1337
  if (isset($context['panelizer_default'])) {
1338
    $entity->panelizer[$view_mode] = $context['panelizer_default'];
1339
    $entity->panelizer[$view_mode]->did = NULL;
1340

    
1341
    // Ensure original values are maintained:
1342
    $entity->panelizer[$view_mode]->entity_id = $entity_id;
1343
    $entity->panelizer[$view_mode]->revision_id = $revision_id;
1344
  }
1345
  else {
1346
    $entity->panelizer[$view_mode]->name = NULL;
1347
    $entity->panelizer[$view_mode]->did = NULL;
1348
  }
1349
}
1350

    
1351
/**
1352
 * Provides the panelizer_set_status_action form.
1353
 */
1354
function panelizer_set_status_action_form($context, &$form_state) {
1355
  $form = array();
1356
  $entity_info = entity_get_info($context['entity_type']);
1357
  $entities = entity_load($context['entity_type'], $form_state['selection']);
1358
  $bundles = array();
1359

    
1360
  $handler = panelizer_entity_plugin_get_handler($context['entity_type']);
1361
  // Collect our list of bundles.
1362
  foreach ($entities as $entity) {
1363
    list($entity_id, $revision_id, $bundle) = entity_extract_ids($context['entity_type'], $entity);
1364
    $bundles[$bundle] = $bundle;
1365
  }
1366

    
1367
  $conditions = array(
1368
    'panelizer_type' => $context['entity_type'],
1369
    'panelizer_key' => $bundles,
1370
  );
1371

    
1372
  ctools_include('export');
1373
  $defaults = ctools_export_load_object('panelizer_defaults', 'conditions', $conditions);
1374

    
1375
  foreach ($defaults as $name => $default) {
1376
    if (empty($default->title)) {
1377
      $default->title = t('Default');
1378
    }
1379
    $options[$default->view_mode][$name] = t('@bundle: @title', array('@bundle' => $entity_info['bundles'][$default->panelizer_key]['label'], '@title' => $default->title));
1380
  }
1381

    
1382
  $view_modes = array();
1383
  foreach ($handler->plugin['view modes'] as $view_mode => $view_mode_info) {
1384
    $view_modes[$view_mode] = $view_mode_info['label'];
1385
  }
1386

    
1387
  $form['panelizer']['#tree'] = TRUE;
1388

    
1389
  foreach ($view_modes as $view_mode => $label) {
1390
    if (empty($options[$view_mode])) {
1391
      unset($view_modes[$view_mode]);
1392
      continue;
1393
    }
1394

    
1395
    natcasesort($options[$view_mode]);
1396
    $panelizers = array(
1397
      'not' => t('Not panelized'),
1398
    ) + $options[$view_mode];
1399

    
1400

    
1401
    $form['panelizer'][$view_mode] = array(
1402
      '#type' => 'select',
1403
      '#title' => t('Panelizer status'),
1404
      '#options' => $panelizers,
1405
      '#states' => array(
1406
        'visible' => array(
1407
          '#panelizer-view-mode' => array('value' => $view_mode),
1408
        ),
1409
      ),
1410
    );
1411
  }
1412

    
1413
  $form['view_mode'] = array(
1414
    '#type' => 'select',
1415
    '#title' => t('View mode'),
1416
    '#options' => $view_modes,
1417
    '#id' => 'panelizer-view-mode',
1418
    '#weight' => -10,
1419
  );
1420

    
1421
  $form['#panelizer_defaults'] = $defaults;
1422
  return $form;
1423
}
1424

    
1425
function panelizer_set_status_action_submit($form, $form_state) {
1426
  $view_mode = $form_state['values']['view_mode'];
1427
  $panelizer = $form_state['values']['panelizer'][$view_mode];
1428

    
1429
  $retval = array(
1430
    'panelizer' => $panelizer,
1431
    'view_mode' => $view_mode,
1432
  );
1433

    
1434
  if ($form_state['values']['panelizer'] != 'not') {
1435
    $retval['panelizer_default'] = $form['#panelizer_defaults'][$panelizer];
1436
  }
1437

    
1438
  return $retval;
1439
}
1440

    
1441
// --------------------------------------------------------------------------
1442
// Miscellaneous helper functions
1443

    
1444
/**
1445
 * Return list of operations.
1446
 *
1447
 * @see hook_panelizer_operations_alter().
1448
 */
1449
function panelizer_operations() {
1450
  $operations = array(
1451
    'settings' => array(
1452
      'menu title' => 'Settings',
1453
      'link title' => t('settings'),
1454
      'admin callback' => 'panelizer_default_settings_page',
1455
      // ctools export ui thinks this is 'edit'.
1456
      'ui path' => 'edit',
1457
    ),
1458
    'context' => array(
1459
      'menu title' => 'Context',
1460
      'link title' => t('context'),
1461
      'admin callback' => 'panelizer_default_context_page',
1462
    ),
1463
    'layout' => array(
1464
      'menu title' => 'Layout',
1465
      'link title' => t('layout'),
1466
      'admin callback' => 'panelizer_default_layout_page',
1467
    ),
1468
    'content' => array(
1469
      'menu title' => 'Content',
1470
      'link title' => t('content'),
1471
      'admin callback' => 'panelizer_default_content_page',
1472
    ),
1473
  );
1474

    
1475
  drupal_alter('panelizer_operations', $operations);
1476

    
1477
  return $operations;
1478
}
1479

    
1480
/**
1481
 * Implements hook_form_alter().
1482
 *
1483
 * Alter the IPE save control form to handle extra Panelizer functionality.
1484
 */
1485
function panelizer_form_panels_ipe_edit_control_form_alter(&$form, &$form_state) {
1486
  if (empty($form_state['renderer'])) {
1487
    return;
1488
  }
1489

    
1490
  $renderer = $form_state['renderer'];
1491

    
1492
  $cache_key = $renderer->display->cache_key;
1493
  list($module, $type, $key) = explode(':', $cache_key, 3);
1494
  if ($module != 'panelizer') {
1495
    return;
1496
  }
1497

    
1498
  if ($type == 'default') {
1499
    return;
1500
  }
1501

    
1502
  // Load the $plugin information
1503
  $handler = panelizer_entity_plugin_get_handler($type);
1504
  if (!$handler) {
1505
    return;
1506
  }
1507

    
1508
  // Get the entity that's being edited.
1509
  list($entity_id, $view_mode) = explode(':', $key);
1510
  $entities = entity_load($handler->entity_type, array($entity_id));
1511
  if (empty($entities[$entity_id])) {
1512
    return;
1513
  }
1514

    
1515
  $entity = $entities[$entity_id];
1516
  list($entity_id, $revision_id, $bundle) = entity_extract_ids($handler->entity_type, $entity);
1517
  $entity_info = entity_get_info($handler->entity_type);
1518

    
1519
  if (empty($entity->panelizer[$view_mode])) {
1520
    return;
1521
  }
1522

    
1523
  $panelizer = $entities[$entity_id]->panelizer[$view_mode];
1524

    
1525
  // If the entity already has customized panelizer data, add the revert button.
1526
  if (!empty($panelizer->did)) {
1527
    if ($handler->has_default_panel($bundle . '.' . $view_mode)) {
1528
      $form['buttons']['revert_default'] = array(
1529
        '#type' => 'submit',
1530
        '#value' => t('Revert to @bundle_name default', array('@bundle_name' => $entity_info['bundles'][$bundle]['label'])),
1531
        '#submit' => array('panels_ipe_revert_to_default'),
1532
        '#attributes' => array('class' => array('panels-ipe-cancel')),
1533
        '#id' => 'panelizer-ipe-revert',
1534
//        '#attributes' => array('onclick' => ''),
1535
      );
1536
      $form_state['panelizer entity'] = $entity;
1537
      $form_state['panelizer bundle'] = $bundle;
1538
      $form_state['panelizer handler'] = $handler;
1539
      $form_state['panelizer view_mode'] = $view_mode;
1540
    }
1541
    return;
1542
  }
1543

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

    
1547
  // Calculate the proper name to add to the cache key, which
1548
  // has some data stripped off of the true name.
1549
  if (empty($panelizer->name)) {
1550
    $name = 'default';
1551
  }
1552
  else {
1553
    $pieces = explode(':', $panelizer->name);
1554
    // Strip off entity type
1555
    array_shift($pieces);
1556
    // Strip off entity bundle
1557
    array_shift($pieces);
1558
    // Strip off view mode
1559
    array_shift($pieces);
1560
    $name = implode(':', $pieces);
1561
  }
1562

    
1563
  // Add another button to save as the default instead:
1564
  $form['buttons']['save_default'] = array(
1565
    '#type' => 'submit',
1566
    '#value' => t('Save as @bundle_name default', array('@bundle_name' => $entity_info['bundles'][$bundle]['label'])),
1567
    '#submit' => array('panels_ipe_change_to_default', 'panels_edit_display_form_submit'),
1568
    '#save-display' => TRUE,
1569
    '#weight' => -1,
1570
    // precalculate the cache key so we don't have to unwind a bunch of stuff
1571
    // in the submit handler.
1572
    '#cache_key' => 'default:' . $handler->entity_type . ':' . $bundle . '.' . $panelizer->view_mode . ':' . $name,
1573
    '#attributes' => array('class' => array('panels-ipe-save')),
1574
    '#id' => 'panelizer-save-default',
1575
  );
1576
}
1577

    
1578
/**
1579
 * Submit handler to save the panelizer default instead of customizing the entity.
1580
 */
1581
function panels_ipe_change_to_default($form, &$form_state) {
1582
  // Change the cache key so that it saves to the default instead of the
1583
  // entity. This works because we're actually editing the original display
1584
  // anyway, and everything else keys off the cache key.
1585
  $form_state['display']->swap_cache_key = $form_state['triggering_element']['#cache_key'];
1586
}
1587

    
1588
/**
1589
 * Submit handler to revert to the default panelizer.
1590
 */
1591
function panels_ipe_revert_to_default($form, &$form_state) {
1592
  // Reduce code complexity due to indirection.
1593
  $handler = $form_state['panelizer handler'];
1594
  $entity = $form_state['panelizer entity'];
1595
  $bundle = $form_state['panelizer bundle'];
1596
  $view_mode = $form_state['panelizer view_mode'];
1597
  $renderer = $form_state['renderer'];
1598

    
1599
  $handler->delete_entity_panelizer($entity, $view_mode);
1600

    
1601
  $name = implode(':', array($handler->entity_type, $bundle, 'default'));
1602
  if ($view_mode != 'page_manager') {
1603
    $name .= ':' . $view_mode;
1604
  }
1605
  $cache_key = $form_state['display']->cache_key;
1606

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

    
1610
  $renderer->display = $display = $panelizer->display;
1611
  $display->cache_key = $cache_key;
1612

    
1613
  $display->context = $handler->get_contexts($panelizer, $entity);
1614

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