Projet

Général

Profil

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

root / drupal7 / sites / all / modules / panels / panels.module @ 73ab1d0a

1 85ad3d82 Assos Assos
<?php
2
3
/**
4 64156087 Assos Assos
 * @file
5 85ad3d82 Assos Assos
 * Core functionality for the Panels engine.
6
 */
7
8 08475715 Assos Assos
define('PANELS_REQUIRED_CTOOLS_API', '2.0.9');
9 e4c061ad Assos Assos
10
/**
11
 * The current working panels version.
12
 *
13
 * In a release, it should be 7.x-3.x, which should match what drush make will
14
 * create. In a dev format, it should be 7.x-3.(x+1)-dev, which will allow
15
 * modules depending on new features in panels to depend on panels > 7.x-3.x.
16
 *
17
 * To define a specific version of Panels as a dependency for another module,
18
 * simply include a dependency line in that module's info file, e.g.:
19
 *   ; Requires Panels v7.x-3.4 or newer.
20
 *   dependencies[] = panels (>=3.4)
21
 */
22 08475715 Assos Assos
define('PANELS_VERSION', '7.x-3.8');
23 e4c061ad Assos Assos
24 85ad3d82 Assos Assos
25 64156087 Assos Assos
// Hide title use to be TRUE/FALSE. So FALSE remains old behavior.
26
define('PANELS_TITLE_FIXED', 0);
27
// And TRUE meant no title.
28
define('PANELS_TITLE_NONE', 1);
29
// And this is the new behavior, where the title field will pick from a pane.
30
define('PANELS_TITLE_PANE', 2);
31 85ad3d82 Assos Assos
32
/**
33
 * Returns the API version of Panels. This didn't exist in 1.
34
 *
35
 * @todo -- this should work more like the CTools API version.
36
 *
37 64156087 Assos Assos
 * @return array
38
 *   An array with the major and minor versions
39 85ad3d82 Assos Assos
 */
40
function panels_api_version() {
41
  return array(3, 1);
42
}
43
44
/**
45 64156087 Assos Assos
 * Implements hook_theme().
46 85ad3d82 Assos Assos
 */
47
function panels_theme() {
48
  // Safety: go away if CTools is not at an appropriate version.
49
  if (!module_invoke('ctools', 'api_version', PANELS_REQUIRED_CTOOLS_API)) {
50
    return array();
51
  }
52
53
  $theme = array();
54
  $theme['panels_layout_link'] = array(
55 64156087 Assos Assos
    'variables' => array(
56
      'title' => NULL,
57
      'id' => NULL,
58
      'image' => NULL,
59
      'link' => NULL,
60
      'class' => NULL,
61
    ),
62 85ad3d82 Assos Assos
  );
63
  $theme['panels_layout_icon'] = array(
64 64156087 Assos Assos
    'variables' => array(
65
      'id' => NULL,
66
      'image' => NULL,
67
      'title' => NULL,
68
    ),
69 85ad3d82 Assos Assos
  );
70
  $theme['panels_pane'] = array(
71 64156087 Assos Assos
    'variables' => array(
72
      'content' => array(),
73
      'pane' => array(),
74
      'display' => array(),
75
    ),
76 85ad3d82 Assos Assos
    'path' => drupal_get_path('module', 'panels') . '/templates',
77
    'template' => 'panels-pane',
78
  );
79
  $theme['panels_common_content_list'] = array(
80
    'variables' => array('display' => NULL),
81
    'file' => 'includes/common.inc',
82
  );
83
  $theme['panels_render_display_form'] = array(
84
    'render element' => 'element',
85
  );
86
87
  $theme['panels_dashboard'] = array(
88
    'variables' => array(),
89
    'path' => drupal_get_path('module', 'panels') . '/templates',
90
    'file' => '../includes/callbacks.inc',
91
    'template' => 'panels-dashboard',
92
  );
93
94
  $theme['panels_dashboard_link'] = array(
95
    'variables' => array('link' => array()),
96
    'path' => drupal_get_path('module', 'panels') . '/templates',
97
    'file' => '../includes/callbacks.inc',
98
    'template' => 'panels-dashboard-link',
99
  );
100
101
  $theme['panels_dashboard_block'] = array(
102
    'variables' => array('block' => array()),
103
    'path' => drupal_get_path('module', 'panels') . '/templates',
104
    'file' => '../includes/callbacks.inc',
105
    'template' => 'panels-dashboard-block',
106
  );
107
108
  $theme['panels_add_content_modal'] = array(
109 64156087 Assos Assos
    'variables' => array(
110
      'renderer' => NULL,
111
      'categories' => array(),
112
      'region' => NULL,
113
      'category' => NULL,
114
      'column_count' => 2,
115
    ),
116 85ad3d82 Assos Assos
    'path' => drupal_get_path('module', 'panels') . '/templates',
117
    'file' => '../includes/add-content.inc',
118
    'template' => 'panels-add-content-modal',
119
  );
120
121
  $theme['panels_add_content_link'] = array(
122 64156087 Assos Assos
    'variables' => array(
123
      'renderer' => NULL,
124
      'region' => NULL,
125
      'content_type' => NULL,
126
    ),
127 85ad3d82 Assos Assos
    'path' => drupal_get_path('module', 'panels') . '/templates',
128
    'file' => '../includes/add-content.inc',
129
    'template' => 'panels-add-content-link',
130
  );
131
132
  // Register layout and style themes on behalf of all of these items.
133
  ctools_include('plugins', 'panels');
134
135
  // No need to worry about files; the plugin has to already be loaded for us
136
  // to even know what the theme function is, so files will be auto included.
137
  $layouts = panels_get_layouts();
138
  foreach ($layouts as $name => $data) {
139
    foreach (array('theme', 'admin theme') as $callback) {
140
      if (!empty($data[$callback])) {
141
        $theme[$data[$callback]] = array(
142 64156087 Assos Assos
          'variables' => array(
143
            'css_id' => NULL,
144
            'content' => NULL,
145
            'settings' => NULL,
146
            'display' => NULL,
147
            'layout' => NULL,
148
            'renderer' => NULL,
149
          ),
150 85ad3d82 Assos Assos
          'path' => $data['path'],
151
          'file' => $data['file'],
152
        );
153
154 64156087 Assos Assos
        // If no theme function exists, assume template.
155 85ad3d82 Assos Assos
        if (!function_exists("theme_$data[theme]")) {
156
          $theme[$data[$callback]]['template'] = str_replace('_', '-', $data[$callback]);
157 64156087 Assos Assos
          // For preprocess.
158
          $theme[$data[$callback]]['file'] = $data['file'];
159 85ad3d82 Assos Assos
        }
160
      }
161
    }
162
  }
163
164
  $styles = panels_get_styles();
165
  foreach ($styles as $name => $data) {
166
    if (!empty($data['render pane'])) {
167
      $theme[$data['render pane']] = array(
168 64156087 Assos Assos
        'variables' => array(
169
          'content' => NULL,
170
          'pane' => NULL,
171
          'display' => NULL,
172
          'style' => NULL,
173
          'settings' => NULL,
174
        ),
175 85ad3d82 Assos Assos
        'path' => $data['path'],
176
        'file' => $data['file'],
177
      );
178
    }
179
    if (!empty($data['render region'])) {
180
      $theme[$data['render region']] = array(
181 64156087 Assos Assos
        'variables' => array(
182
          'display' => NULL,
183
          'owner_id' => NULL,
184
          'panes' => NULL,
185
          'settings' => NULL,
186
          'region_id' => NULL,
187
          'style' => NULL,
188
        ),
189 85ad3d82 Assos Assos
        'path' => $data['path'],
190
        'file' => $data['file'],
191
      );
192
    }
193
194
    if (!empty($data['hook theme'])) {
195
      if (is_array($data['hook theme'])) {
196
        $theme += $data['hook theme'];
197
      }
198 64156087 Assos Assos
      elseif (function_exists($data['hook theme'])) {
199 85ad3d82 Assos Assos
        $data['hook theme']($theme, $data);
200
      }
201
    }
202
  }
203
  return $theme;
204
}
205
206
/**
207 64156087 Assos Assos
 * Implements hook_menu().
208 85ad3d82 Assos Assos
 */
209
function panels_menu() {
210
  // Safety: go away if CTools is not at an appropriate version.
211
  if (!module_invoke('ctools', 'api_version', PANELS_REQUIRED_CTOOLS_API)) {
212
    return array();
213
  }
214
  $items = array();
215
216
  // Base AJAX router callback.
217
  $items['panels/ajax'] = array(
218
    'access arguments' => array('access content'),
219
    'page callback' => 'panels_ajax_router',
220
    'theme callback' => 'ajax_base_page_theme',
221
    'delivery callback' => 'ajax_deliver',
222
    'type' => MENU_CALLBACK,
223
  );
224
225
  $admin_base = array(
226
    'file' => 'includes/callbacks.inc',
227
    'access arguments' => array('use panels dashboard'),
228
  );
229
  // Provide a nice location for a panels admin panel.
230
  $items['admin/structure/panels'] = array(
231
    'title' => 'Panels',
232
    'page callback' => 'panels_admin_page',
233
    'description' => 'Get a bird\'s eye view of items related to Panels.',
234
  ) + $admin_base;
235
236
  $items['admin/structure/panels/dashboard'] = array(
237
    'title' => 'Dashboard',
238
    'page callback' => 'panels_admin_page',
239
    'type' => MENU_DEFAULT_LOCAL_TASK,
240
    'weight' => -10,
241
  ) + $admin_base;
242
243
  $items['admin/structure/panels/settings'] = array(
244
    'title' => 'Settings',
245
    'page callback' => 'drupal_get_form',
246
    'page arguments' => array('panels_admin_settings_page'),
247
    'type' => MENU_LOCAL_TASK,
248
  ) + $admin_base;
249
250
  $items['admin/structure/panels/settings/general'] = array(
251
    'title' => 'General',
252
    'page callback' => 'drupal_get_form',
253
    'page arguments' => array('panels_admin_settings_page'),
254
    'access arguments' => array('administer page manager'),
255
    'type' => MENU_DEFAULT_LOCAL_TASK,
256
    'weight' => -10,
257
  ) + $admin_base;
258
259
  if (module_exists('page_manager')) {
260
    $items['admin/structure/panels/settings/panel-page'] = array(
261
      'title' => 'Panel pages',
262
      'page callback' => 'panels_admin_panel_context_page',
263
      'type' => MENU_LOCAL_TASK,
264
      'weight' => -10,
265
    ) + $admin_base;
266
  }
267
268
  ctools_include('plugins', 'panels');
269
  $layouts = panels_get_layouts();
270
  foreach ($layouts as $name => $data) {
271
    if (!empty($data['hook menu'])) {
272
      if (is_array($data['hook menu'])) {
273
        $items += $data['hook menu'];
274
      }
275 64156087 Assos Assos
      elseif (function_exists($data['hook menu'])) {
276 85ad3d82 Assos Assos
        $data['hook menu']($items, $data);
277
      }
278
    }
279
  }
280
  return $items;
281
}
282
283
/**
284
 * Menu loader function to load a cache item for Panels AJAX.
285
 *
286
 * This load all of the includes needed to perform AJAX, and loads the
287
 * cache object and makes sure it is valid.
288
 */
289
function panels_edit_cache_load($cache_key) {
290
  ctools_include('display-edit', 'panels');
291
  ctools_include('plugins', 'panels');
292
  ctools_include('ajax');
293
  ctools_include('modal');
294
  ctools_include('context');
295
296
  return panels_edit_cache_get($cache_key);
297
}
298
299
/**
300 64156087 Assos Assos
 * Implements hook_init().
301 85ad3d82 Assos Assos
 */
302
function panels_init() {
303
  // Safety: go away if CTools is not at an appropriate version.
304
  if (!module_invoke('ctools', 'api_version', PANELS_REQUIRED_CTOOLS_API)) {
305
    if (user_access('administer site configuration')) {
306
      drupal_set_message(t('Panels is enabled but CTools is out of date. All Panels modules are disabled until CTools is updated. See the status page for more information.'), 'error');
307
    }
308
    return;
309
  }
310
311
  ctools_add_css('panels', 'panels');
312
}
313
314
/**
315 64156087 Assos Assos
 * Implements hook_permission().
316 85ad3d82 Assos Assos
 *
317
 * @todo Almost all of these need to be moved into pipelines.
318
 */
319
function panels_permission() {
320
  return array(
321
    'use panels dashboard' => array(
322
      'title' => t("Use Panels Dashboard"),
323 e4c061ad Assos Assos
      'description' => t('Allows a user to access the <a href="@url">Panels Dashboard</a>.', array('@url' => url('admin/structure/panels'))),
324 85ad3d82 Assos Assos
    ),
325 64156087 Assos Assos
    // @todo
326
    'view pane admin links' => array(
327 85ad3d82 Assos Assos
      'title' => t("View administrative links on Panel panes"),
328 64156087 Assos Assos
      'description' => "",
329 85ad3d82 Assos Assos
    ),
330 64156087 Assos Assos
    // @todo should we really have a global perm for this, or should it be moved into a pipeline question?
331
    'administer pane access' => array(
332 85ad3d82 Assos Assos
      'title' => t("Configure access settings on Panel panes"),
333
      'description' => t("Access rules (often also called visibility rules) can be configured on a per-pane basis. This permission allows users to configure those settings."),
334
    ),
335
    'use panels in place editing' => array(
336
      'title' => t("Use the Panels In-Place Editor"),
337
      'description' => t("Allows a user to utilize Panels' In-Place Editor."),
338
    ),
339
    'change layouts in place editing' => array(
340
      'title' => t("Change layouts with the Panels In-Place Editor"),
341
      'description' => t("Allows a user to change layouts with the IPE."),
342
    ),
343 136a805a Assos Assos
    'bypass access in place editing' => array(
344
      'title' => t("Bypass access checks when using Panels In-Place Editor"),
345
      'description' => t("Allows using IPE even if user does not have additional permissions granted by other modules."),
346
      'restrict access' => TRUE,
347
    ),
348 85ad3d82 Assos Assos
    'administer advanced pane settings' => array(
349
      'title' => t("Configure advanced settings on Panel panes"),
350 64156087 Assos Assos
      'description' => "",
351 85ad3d82 Assos Assos
    ),
352
    'administer panels layouts' => array(
353
      'title' => t("Administer Panels layouts"),
354
      'description' => t("Allows a user to administer exported Panels layout plugins & instances."),
355
    ),
356
    'administer panels styles' => array(
357
      'title' => t("Administer Panels styles"),
358 08475715 Assos Assos
      'description' => t("DEPRECATED: Modules using this permission should use specific style permissions. See Issue #2329419 for more info."),
359
    ),
360
    'administer panels display styles' => array(
361
      'title' => t("Administer Panels display styles"),
362
      'description' => t("Allows a user to administer the styles of Panel displays."),
363
    ),
364
    'administer panels pane styles' => array(
365
      'title' => t("Administer Panels pane styles"),
366 85ad3d82 Assos Assos
      'description' => t("Allows a user to administer the styles of Panel panes."),
367
    ),
368 08475715 Assos Assos
    'administer panels region styles' => array(
369
      'title' => t("Administer Panels region styles"),
370
      'description' => t("Allows a user to administer the styles of Panel regions."),
371
    ),
372 85ad3d82 Assos Assos
    'use panels caching features' => array(
373
      'title' => t("Configure caching settings on Panels"),
374
      'description' => t("Allows a user to configure caching on Panels displays and panes."),
375
    ),
376
    'use panels locks' => array(
377
      'title' => t('Use panel locks'),
378
      'description' => t('Allows a user to lock and unlock panes in a panel display.'),
379
    ),
380 5a7e6170 Florent Torregrosa
    'use ipe with page manager' => array(
381
      'title' => t("Use the Panels In-Place Editor with Page Manager"),
382
      'description' => t('Allows users with access to the In-Place editor to administer page manager pages. This permission is only needed for users without "use page manager" access.'),
383
    ),
384 85ad3d82 Assos Assos
  );
385
}
386
387 5a7e6170 Florent Torregrosa
/**
388
 * Implements hook_flush_caches().
389
 */
390
function panels_flush_caches() {
391 e4c061ad Assos Assos
  if (db_table_exists('cache_panels')) {
392
    return array('cache_panels');
393
  }
394 5a7e6170 Florent Torregrosa
}
395
396 64156087 Assos Assos
/**
397
 * CTools hook implementations.
398
 *
399
 * These aren't core Drupal hooks but they are just as important.
400
 */
401 85ad3d82 Assos Assos
402
/**
403 64156087 Assos Assos
 * Implements hook_ctools_plugin_directory().
404 85ad3d82 Assos Assos
 */
405
function panels_ctools_plugin_directory($module, $plugin) {
406 64156087 Assos Assos
  // To let the system know we implement task and task_handler plugins.
407 85ad3d82 Assos Assos
  // Safety: go away if CTools is not at an appropriate version.
408
  if (!module_invoke('ctools', 'api_version', PANELS_REQUIRED_CTOOLS_API)) {
409
    return;
410
  }
411
412
  // We don't support the 'ctools' 'cache' plugin and pretending to causes
413
  // errors when they're in use.
414
  if ($module == 'ctools' && $plugin == 'cache') {
415 64156087 Assos Assos
    // If we did we'd make a plugin/ctools_cache or something.
416 85ad3d82 Assos Assos
    return;
417
  }
418
419
  if ($module == 'page_manager' || $module == 'panels' || $module == 'ctools' || $module == 'stylizer') {
420
    // Panels and CTools both implement a 'cache' plugin but we don't implement
421
    // the CTools version.
422
    if ($module == 'ctools' && $plugin == 'cache') {
423
      return;
424
    }
425
    return 'plugins/' . $plugin;
426
  }
427
}
428
429
/**
430
 * Implements hook_ctools_plugin_type().
431
 *
432
 * Register layout, style, cache, and display_renderer plugin types, declaring
433
 * relevant plugin type information as necessary.
434
 */
435
function panels_ctools_plugin_type() {
436
  return array(
437
    'layouts' => array(
438 64156087 Assos Assos
      // We can define layouts in themes.
439
      'load themes' => TRUE,
440 85ad3d82 Assos Assos
      'process' => 'panels_layout_process',
441
      'child plugins' => TRUE,
442
    ),
443
    'styles' => array(
444
      'load themes' => TRUE,
445
      'process' => 'panels_plugin_styles_process',
446
      'child plugins' => TRUE,
447
    ),
448
    'cache' => array(),
449
    'display_renderers' => array(
450
      'classes' => array('renderer'),
451
    ),
452 136a805a Assos Assos
    'panels_storage' => array(),
453 85ad3d82 Assos Assos
  );
454
}
455
456
/**
457
 * Ensure a layout has a minimal set of data.
458
 */
459
function panels_layout_process(&$plugin) {
460
  $plugin += array(
461
    'category' => t('Miscellaneous'),
462
    'description' => '',
463
  );
464
}
465
466
/**
467 64156087 Assos Assos
 * Implements hook_ctools_plugin_api().
468 85ad3d82 Assos Assos
 */
469
function panels_ctools_plugin_api($owner, $api) {
470 64156087 Assos Assos
  // Inform CTools about version information for various plugins implemented by
471
  // panels.
472 85ad3d82 Assos Assos
  if ($owner == 'panels' && $api == 'styles') {
473
    // As of 6.x-3.6, Panels has a slightly new system for style plugins.
474
    return array('version' => 2.0);
475
  }
476
477
  if ($owner == 'panels' && $api == 'pipelines') {
478
    return array(
479
      'version' => 1,
480
      'path' => drupal_get_path('module', 'panels') . '/includes',
481
    );
482
  }
483
}
484
485
/**
486 64156087 Assos Assos
 * Implements hook_views_api().
487 85ad3d82 Assos Assos
 */
488
function panels_views_api() {
489
  return array(
490
    'api' => 2,
491
    'path' => drupal_get_path('module', 'panels') . '/plugins/views',
492
  );
493
}
494
495
/**
496
 * Perform additional processing on a style plugin.
497
 *
498
 * Currently this is only being used to apply versioning information to style
499
 * plugins in order to ensure the legacy renderer passes the right type of
500
 * parameters to a style plugin in a hybrid environment of both new and old
501
 * plugins.
502
 *
503
 * @param array $plugin
504
 *   The style plugin that is being processed.
505
 * @param array $info
506
 *   The style plugin type info array.
507 64156087 Assos Assos
 *
508
 * @see _ctools_process_data()
509 85ad3d82 Assos Assos
 */
510
function panels_plugin_styles_process(&$plugin, $info) {
511
  $plugin += array(
512
    'weight' => 0,
513
  );
514
515
  $compliant_modules = ctools_plugin_api_info('panels', 'styles', 2.0, 2.0);
516
  $plugin['version'] = empty($compliant_modules[$plugin['module']]) ? 1.0 : $compliant_modules[$plugin['module']]['version'];
517
}
518
519
/**
520
 * Declare what style types Panels uses.
521
 */
522
function panels_ctools_style_base_types() {
523
  return array(
524
    'region' => array(
525
      'title' => t('Panel region'),
526
      'preview' => 'panels_stylizer_region_preview',
527 64156087 Assos Assos
      'theme variables' => array(
528
        'settings' => NULL,
529
        'class' => NULL,
530
        'content' => NULL,
531
      ),
532 85ad3d82 Assos Assos
    ),
533
    'pane' => array(
534
      'title' => t('Panel pane'),
535
      'preview' => 'panels_stylizer_pane_preview',
536 64156087 Assos Assos
      'theme variables' => array(
537
        'settings' => NULL,
538
        'content' => NULL,
539
        'pane' => NULL,
540
        'display' => NULL,
541
      ),
542 85ad3d82 Assos Assos
    ),
543
  );
544
}
545
546 64156087 Assos Assos
/**
547
 * Generates Lorem Ipsum.
548
 *
549
 * @return string
550
 *   Lorem ipsum string.
551
 */
552 85ad3d82 Assos Assos
function panels_stylizer_lipsum() {
553 64156087 Assos Assos
  return <<<LIPSUM
554
    <p>
555
      Lorem ipsum dolor sit amet, consectetur adipiscing elit. Phasellus at 
556
      velit dolor. Donec egestas tellus sit amet urna rhoncus adipiscing. Proin 
557
      nec porttitor sem. Maecenas aliquam, purus nec tempus dignissim, nulla arcu
558
      aliquam diam, non tincidunt massa ante vel dolor. Aliquam sapien sapien,
559
      tincidunt id tristique at, pretium sagittis libero.
560
    </p>
561
    <p>
562
      Nulla facilisi. Curabitur lacinia, tellus sed tristique consequat, diam
563
      lorem scelerisque felis, at dictum purus augue facilisis lorem. Duis
564
      pharetra dignissim rutrum. Curabitur ac elit id dui dapibus tincidunt.
565
      Nulla eget sem quam, non eleifend eros. Cras porttitor tempus lectus ac
566
      scelerisque. Curabitur vehicula bibendum lorem, vitae ornare ligula
567
      venenatis ut.
568
    </p>
569
LIPSUM;
570 85ad3d82 Assos Assos
}
571
572
/**
573
 * Generate a preview given the current settings.
574
 */
575
function panels_stylizer_region_preview($plugin, $settings) {
576
  ctools_stylizer_add_css($plugin, $settings);
577 64156087 Assos Assos
  return theme(
578
    $plugin['theme'],
579
    array(
580
      'settings' => $settings,
581
      'class' => ctools_stylizer_get_css_class($plugin, $settings),
582
      'content' => panels_stylizer_lipsum(),
583
    )
584
  );
585 85ad3d82 Assos Assos
}
586
587
/**
588
 * Generate a preview given the current settings.
589
 */
590
function panels_stylizer_pane_preview($plugin, $settings) {
591
  ctools_stylizer_add_css($plugin, $settings);
592
  $pane = new stdClass();
593
594 64156087 Assos Assos
  $content = new stdClass();
595 85ad3d82 Assos Assos
  $content->title = t('Lorem ipsum');
596
  $content->content = panels_stylizer_lipsum();
597
  $content->type = 'dummy';
598
  $content->subtype = 'dummy';
599
600
  $content->css_class = ctools_stylizer_get_css_class($plugin, $settings);
601
602
  $display = new panels_display();
603
604
  if (!empty($plugin['theme'])) {
605 64156087 Assos Assos
    return theme(
606
      $plugin['theme'],
607
      array(
608
        'settings' => $settings,
609
        'content' => $content,
610
        'pane' => $pane,
611
        'display' => $display,
612
      )
613
    );
614 85ad3d82 Assos Assos
  }
615
  else {
616 64156087 Assos Assos
    return theme(
617
      'panels_pane',
618
      array(
619
        'content' => $content,
620
        'pane' => $pane,
621
        'display' => $display,
622
      )
623
    );
624 85ad3d82 Assos Assos
  }
625
}
626
627 64156087 Assos Assos
/**
628
 * Panels display editing.
629
 */
630 85ad3d82 Assos Assos
631
/**
632 64156087 Assos Assos
 * @defgroup mainapi Functions comprising the main panels API.
633 85ad3d82 Assos Assos
 */
634
635
/**
636
 * Main API entry point to edit a panel display.
637
 *
638 64156087 Assos Assos
 * Sample implementations utiltizing the the complex $destination behavior can
639
 * be found in panels_page_edit_content() and, in a separate contrib module,
640
 * OG Blueprints (http://drupal.org/project/og_blueprints),
641
 * og_blueprints_blueprint_edit().
642 85ad3d82 Assos Assos
 *
643 64156087 Assos Assos
 * @param object $display
644
 *   Instanceof panels_display.
645
 *
646
 *   A fully loaded panels $display object, as returned from
647
 *   panels_load_display(). Merely passing a did is NOT sufficient.
648
 *   Note that 'fully loaded' means the $display must already be loaded with
649
 *   any contexts the caller wishes to have set for the display.
650
 * @param mixed $destination
651
 *   The redirect destination that the user should be taken to on form
652
 *   submission or cancellation. With panels_edit, $destination has complex
653
 *   effects on the return values of panels_edit() once the form has been
654
 *   submitted. See the explanation of the return value below to understand the
655
 *   different types of values returned by panels_edit() at different stages of
656
 *   FAPI. Under most circumstances, simply passing in drupal_get_destination()
657
 *   is all that's necessary.
658
 * @param array $content_types
659
 *   An associative array of allowed content types, typically as returned from
660
 *   panels_common_get_allowed_types(). Note that context partially governs
661
 *   available content types, so you will want to create any relevant contexts
662
 *   using panels_create_context() or panels_create_context_empty() to make sure
663
 *   all the appropriate content types are available.
664
 *
665
 * @return mixed
666
 *   Because the functions called by panels_edit() invoke the form API,
667
 *   this function returns different values depending on the stage of form
668
 *   submission we're at. In Drupal 5, the phase of form submission is indicated
669
 *   by the contents of $_POST['op']. Here is what you'll get at different
670
 *   stages:
671
 *     -  If !$_POST['op']: then we're on on the initial passthrough and the
672
 *        form is being rendered, so it's the $form itself that's being
673
 *        returned. Because negative margins, a common CSS technique, bork the
674
 *        display editor's ajax drag-and-drop, it's important that the $output
675
 *        be printed, not returned. Use this syntax in the caller function:
676
 *        print theme('page', panels_edit($display, $destination, $content_types), FALSE);
677
 *     -  If $_POST['op'] == t('Cancel'): form submission has been cancelled.
678
 *        If empty($destination) == FALSE, then there is no return value and the
679
 *        panels API takes care of redirecting to $destination.
680
 *        If empty($destination) == TRUE, then there's still no return value,
681
 *        but the caller function has to take care of form redirection.
682
 *     -  If $_POST['op'] == ('Save'): the form has been submitted successfully
683
 *        and has run through panels_edit_display_submit().
684
 *        $output depends on the value of $destination:
685
 *     -  If empty($destination) == TRUE: $output contains the modified $display
686
 *        object, and no redirection will occur. This option is useful if the
687
 *        caller needs to perform additional operations on or with the modified
688
 *        $display before the page request is complete. Using hook_form_alter()
689
 *        to add an additional submit handler is typically the preferred method
690
 *        for something like this, but there are certain use cases where that is
691
 *        infeasible and $destination = NULL should be used instead. If this
692
 *        method is employed, the caller will need to handle form redirection.
693
 *        Note that having $_REQUEST['destination'] set, whether via
694
 *        drupal_get_destination() or some other method, will NOT interfere with
695
 *        this functionality; consequently, you can use drupal_get_destination()
696
 *        to safely store your desired redirect in the caller function, then
697
 *        simply use drupal_goto() once panels_edit() has done its business.
698
 *     -  If empty($destination) == FALSE: the form will redirect to the URL
699
 *        string given in $destination and NO value will be returned.
700 85ad3d82 Assos Assos
 *
701 64156087 Assos Assos
 * @ingroup mainapi
702 85ad3d82 Assos Assos
 */
703
function panels_edit($display, $destination = NULL, $content_types = NULL, $title = FALSE) {
704
  ctools_include('display-edit', 'panels');
705
  ctools_include('ajax');
706
  ctools_include('plugins', 'panels');
707
  return _panels_edit($display, $destination, $content_types, $title);
708
}
709
710
/**
711
 * API entry point for selecting a layout for a given display.
712
 *
713 64156087 Assos Assos
 * Layout selection is nothing more than a list of radio items encompassing the
714
 * available layouts for this display, as defined by .inc files in the
715
 * panels/layouts subdirectory. The only real complexity occurs when a user
716
 * attempts to change the layout of a display that has some content in it.
717 85ad3d82 Assos Assos
 *
718 64156087 Assos Assos
 * @param object $display
719
 *   A fully loaded panels $display object, as returned from
720
 *   panels_load_display(). Merely passing a did is NOT sufficient.
721 85ad3d82 Assos Assos
 * @param string $finish
722 64156087 Assos Assos
 *   A string that will be used for the text of the form submission button. If
723
 *   no value is provided, then the form submission button will default to
724
 *   t('Save').
725 85ad3d82 Assos Assos
 * @param mixed $destination
726 64156087 Assos Assos
 *   Basic usage is a string containing the URL that the form should redirect to
727
 *   upon submission. For a discussion of advanced usages, see panels_edit().
728 85ad3d82 Assos Assos
 * @param mixed $allowed_layouts
729 64156087 Assos Assos
 *   Allowed layouts has three different behaviors that depend on which of three
730
 *   value types are passed in by the caller:
731
 *     #- if $allowed_layouts instanceof panels_allowed_layouts
732
 *        (includes subclasses): the most complex use of the API. The caller is
733
 *        passing in a loaded panels_allowed_layouts object that the client
734
 *        module previously created and stored somewhere using a custom storage
735
 *        mechanism.
736
 *     #- if is_string($allowed_layouts): the string will be used in a call to
737
 *        variable_get() which will call the
738
 *        $allowed_layouts . '_allowed_layouts' var. If the data was stored
739
 *        properly in the system var, the $allowed_layouts object will be
740
 *        unserialized and recreated.
741
 *     #- if is_null($allowed_layouts): the default behavior, which also
742
 *        provides backwards compatibility for implementations of the Panels2
743
 *        API written before beta4. In this case, a dummy panels_allowed_layouts
744
 *        object is created which does not restrict any layouts. Subsequent
745
 *        behavior is indistinguishable from pre-beta4 behavior.
746
 *
747
 * @return mixed
748
 *   Can return nothing, or a modified $display object, or a redirection string;
749
 *   return values for the panels_edit* family of functions are quite complex.
750
 *   See panels_edit() for detailed discussion.
751
 *
752 85ad3d82 Assos Assos
 * @see panels_edit()
753 64156087 Assos Assos
 * @see panels_common_set_allowed_layouts()
754 85ad3d82 Assos Assos
 */
755
function panels_edit_layout($display, $finish, $destination = NULL, $allowed_layouts = NULL) {
756
  ctools_include('display-layout', 'panels');
757
  ctools_include('plugins', 'panels');
758
  return _panels_edit_layout($display, $finish, $destination, $allowed_layouts);
759
}
760
761 64156087 Assos Assos
/**
762
 * Panels database functions.
763
 */
764 85ad3d82 Assos Assos
765
/**
766 64156087 Assos Assos
 * Forms the basis of a panel display.
767 85ad3d82 Assos Assos
 */
768
class panels_display {
769 64156087 Assos Assos
  public $args = array();
770
  public $content = array();
771
  public $panels = array();
772
  public $incoming_content = NULL;
773
  public $css_id = NULL;
774
  public $context = array();
775
  public $did = 'new';
776
  public $renderer = 'standard';
777
778
  /**
779
   * Add a pane.
780
   */
781
  public function add_pane(&$pane, $location = NULL) {
782 85ad3d82 Assos Assos
    // If no location specified, use what's set in the pane.
783
    if (empty($location)) {
784
      $location = $pane->panel;
785
    }
786
    else {
787
      $pane->panel = $location;
788
    }
789
790 5a7e6170 Florent Torregrosa
    // Generate a permanent uuid for this pane, and use
791
    // it as a temporary pid.
792
    $pane->uuid = ctools_uuid_generate();
793
    $pane->pid = 'new-' . $pane->uuid;
794 85ad3d82 Assos Assos
795 64156087 Assos Assos
    // Add the pane to the appropriate spots.
796 85ad3d82 Assos Assos
    $this->content[$pane->pid] = &$pane;
797
    $this->panels[$location][] = $pane->pid;
798
  }
799
800 64156087 Assos Assos
  /**
801
   * Duplicate a pane.
802
   */
803
  public function duplicate_pane($pid, $location = FALSE) {
804 85ad3d82 Assos Assos
    $pane = $this->clone_pane($pid);
805
    $this->add_pane($pane, $location);
806
  }
807
808
  /**
809
   * Get the title from a display.
810
   *
811
   * The display must have already been rendered, or the setting to set the
812
   * display's title from a pane's title will not have worked.
813
   *
814 64156087 Assos Assos
   * @return mixed
815
   *   The title to use. If NULL, this means to let any default title that may
816
   *   be in use pass through. i.e, do not actually set the title.
817 85ad3d82 Assos Assos
   */
818 64156087 Assos Assos
  public function get_title() {
819 85ad3d82 Assos Assos
    switch ($this->hide_title) {
820
      case PANELS_TITLE_NONE:
821
        return '';
822
823
      case PANELS_TITLE_PANE:
824
        return isset($this->stored_pane_title) ? $this->stored_pane_title : '';
825
826
      case PANELS_TITLE_FIXED:
827 64156087 Assos Assos
      case FALSE;
828
        // For old exported panels that are not in the database.
829 85ad3d82 Assos Assos
        if (!empty($this->title)) {
830
          return filter_xss_admin(ctools_context_keyword_substitute($this->title, array(), $this->context));
831
        }
832
        return NULL;
833
    }
834
  }
835
836
  /**
837
   * Render this panels display.
838
   *
839
   * After checking to ensure the designated layout plugin is valid, a
840
   * display renderer object is spawned and runs its rendering logic.
841
   *
842
   * @param mixed $renderer
843
   *    An instantiated display renderer object, or the name of a display
844
   *    renderer plugin+class to be fetched. Defaults to NULL. When NULL, the
845
   *    predesignated display renderer will be used.
846 64156087 Assos Assos
   *
847
   * @return mixed
848
   *    NULL or output of render function.
849 85ad3d82 Assos Assos
   */
850 64156087 Assos Assos
  public function render($renderer = NULL) {
851 85ad3d82 Assos Assos
    $layout = panels_get_layout($this->layout);
852
    if (!$layout) {
853
      return NULL;
854
    }
855
856
    // If we were not given a renderer object, load it.
857
    if (!is_object($renderer)) {
858
      // If the renderer was not specified, default to $this->renderer
859
      // which is either standard or was already set for us.
860
      $renderer = panels_get_renderer_handler(!empty($renderer) ? $renderer : $this->renderer, $this);
861
      if (!$renderer) {
862
        return NULL;
863
      }
864
    }
865
866
    $output = '';
867
    // Let modules act just prior to render.
868
    foreach (module_implements('panels_pre_render') as $module) {
869
      $function = $module . '_panels_pre_render';
870
      $output .= $function($this, $renderer);
871
    }
872
873
    $output .= $renderer->render();
874
875
    // Let modules act just after render.
876
    foreach (module_implements('panels_post_render') as $module) {
877
      $function = $module . '_panels_post_render';
878
      $output .= $function($this, $renderer);
879
    }
880
    return $output;
881
  }
882 136a805a Assos Assos
883
  /**
884
   * Determine if the given user can perform the requested operation.
885
   *
886
   * @param string $op
887
   *   An operation like: create, read, update, or delete.
888
   * @param object $account
889
   *   (optional) The account to check access for.
890
   *
891
   * @return bool
892
   *   TRUE if access is granted; otherwise FALSE.
893
   */
894 64156087 Assos Assos
  public function access($op, $account = NULL) {
895 136a805a Assos Assos
    global $user;
896
897
    if (!$account) {
898
      $account = $user;
899
    }
900
901
    // Even administrators need to go through the access system. However, to
902
    // support legacy plugins, user 1 gets full access no matter what.
903
    if ($account->uid == 1) {
904
      return TRUE;
905
    }
906
907
    if (!in_array($op, array('create', 'read', 'update', 'delete', 'change layout'))) {
908
      return FALSE;
909
    }
910
911
    if (empty($this->storage_type) || empty($this->storage_id)) {
912
      return FALSE;
913
    }
914
915
    if ($this->storage_type == 'unknown') {
916
      return FALSE;
917
    }
918
919
    $storage_plugin = panels_get_panels_storage_plugin($this->storage_type);
920
    if (!$storage_plugin) {
921
      return FALSE;
922
    }
923
924
    $access_callback = panels_plugin_get_function('panels_storage', $storage_plugin, 'access callback');
925
    if (!$access_callback) {
926
      return FALSE;
927
    }
928
929
    return $access_callback($this->storage_type, $this->storage_id, $op, $account);
930
  }
931 64156087 Assos Assos
932 85ad3d82 Assos Assos
}
933
934
/**
935 64156087 Assos Assos
 * End of 'defgroup mainapi', although other functions are specifically added later.
936 85ad3d82 Assos Assos
 */
937
938
/**
939
 * Creates a new display, setting the ID to our magic new id.
940
 */
941
function panels_new_display() {
942
  ctools_include('export');
943
  $display = ctools_export_new_object('panels_display', FALSE);
944
  $display->did = 'new';
945
  return $display;
946
}
947
948
/**
949
 * Create a new pane.
950
 *
951
 * @todo -- use schema API for some of this?
952
 */
953
function panels_new_pane($type, $subtype, $set_defaults = FALSE) {
954
  ctools_include('export');
955
  $pane = ctools_export_new_object('panels_pane', FALSE);
956
  $pane->pid = 'new';
957
  $pane->type = $type;
958
  $pane->subtype = $subtype;
959
  if ($set_defaults) {
960
    ctools_include('content');
961
    $content_type = ctools_get_content_type($type);
962
    $content_subtype = ctools_content_get_subtype($content_type, $subtype);
963
    $pane->configuration = ctools_content_get_defaults($content_type, $content_subtype);
964
  }
965 e4c061ad Assos Assos
  drupal_alter('panels_new_pane', $pane);
966 85ad3d82 Assos Assos
967
  return $pane;
968
}
969
970
/**
971
 * Load and fill the requested $display object(s).
972
 *
973
 * Helper function primarily for for panels_load_display().
974
 *
975
 * @param array $dids
976 64156087 Assos Assos
 *   An indexed array of dids to be loaded from the database.
977 85ad3d82 Assos Assos
 *
978 64156087 Assos Assos
 * @return array
979
 *   An array of displays, keyed by their display dids.
980 85ad3d82 Assos Assos
 *
981
 * @todo schema API can drasticly simplify this code.
982
 */
983
function panels_load_displays($dids) {
984
  $displays = array();
985
  if (empty($dids) || !is_array($dids)) {
986
    return $displays;
987
  }
988
989 64156087 Assos Assos
  $result = db_query(
990
    "SELECT * FROM {panels_display} WHERE did IN (:dids)",
991
    array(':dids' => $dids)
992
  );
993 85ad3d82 Assos Assos
994
  ctools_include('export');
995
  foreach ($result as $obj) {
996
    $displays[$obj->did] = ctools_export_unpack_object('panels_display', $obj);
997
    // Modify the hide_title field to go from a bool to an int if necessary.
998
  }
999
1000 64156087 Assos Assos
  $result = db_query(
1001
    "SELECT * FROM {panels_pane} WHERE did IN (:dids) ORDER BY did, panel, position",
1002
    array(':dids' => $dids)
1003
  );
1004 85ad3d82 Assos Assos
  foreach ($result as $obj) {
1005
    $pane = ctools_export_unpack_object('panels_pane', $obj);
1006
1007
    $displays[$pane->did]->panels[$pane->panel][] = $pane->pid;
1008
    $displays[$pane->did]->content[$pane->pid] = $pane;
1009
  }
1010
  return $displays;
1011
}
1012
1013
/**
1014
 * Load a single display.
1015
 *
1016
 * @param int $did
1017 64156087 Assos Assos
 *   The display id (did) of the display to be loaded.
1018 85ad3d82 Assos Assos
 *
1019 64156087 Assos Assos
 * @return object $display
1020
 *   Returns a partially-loaded panels_display object. $display objects returned
1021
 *   from this function have only the following data:
1022 85ad3d82 Assos Assos
 *    - $display->did (the display id)
1023
 *    - $display->name (the 'name' of the display, where applicable - it often isn't)
1024
 *    - $display->layout (a string with the system name of the display's layout)
1025
 *    - $display->panel_settings (custom layout style settings contained in an associative array; NULL if none)
1026
 *    - $display->layout_settings (panel size and configuration settings for Flexible layouts; NULL if none)
1027
 *    - $display->css_id (the special css_id that has been assigned to this display, if any; NULL if none)
1028
 *    - $display->content (an array of pane objects, keyed by pane id (pid))
1029
 *    - $display->panels (an associative array of panel regions, each an indexed array of pids in the order they appear in that region)
1030
 *    - $display->cache (any relevant data from panels_simple_cache)
1031
 *    - $display->args
1032
 *    - $display->incoming_content
1033 64156087 Assos Assos
 *   While all of these members are defined, $display->context is NEVER defined in the returned $display;
1034
 *   it must be set using one of the ctools_context_create() functions.
1035 85ad3d82 Assos Assos
 *
1036 64156087 Assos Assos
 * @ingroup mainapi
1037 85ad3d82 Assos Assos
 */
1038
function panels_load_display($did) {
1039
  $displays = panels_load_displays(array($did));
1040
  if (!empty($displays)) {
1041
    return array_shift($displays);
1042
  }
1043
}
1044
1045
/**
1046
 * Save a display object.
1047
 *
1048 5a7e6170 Florent Torregrosa
 * Note that a new $display only receives a real did once it is run through
1049
 * this function, and likewise for the pid of any new pane.
1050
 *
1051
 * Until then, a new display uses a string placeholder, 'new', in place of
1052
 * a real did, and a new pane (whether on a new $display or not) appends a
1053
 * universally-unique identifier (which is stored permanently in the 'uuid'
1054
 * field). This format is also used in place of the real pid for exports.
1055 85ad3d82 Assos Assos
 *
1056 64156087 Assos Assos
 * @param object $display
1057
 *   The display object to be saved. Passed by reference so the caller need not
1058
 *   use the return value for any reason except convenience.
1059 85ad3d82 Assos Assos
 *
1060 64156087 Assos Assos
 * @return object $display
1061
 *   This display panel display object to return.
1062
 *
1063
 * @ingroup mainapi
1064 85ad3d82 Assos Assos
 */
1065
function panels_save_display(&$display) {
1066
  $update = (isset($display->did) && is_numeric($display->did)) ? array('did') : array();
1067 5a7e6170 Florent Torregrosa
  if (empty($display->uuid) || !ctools_uuid_is_valid($display->uuid)) {
1068
    $display->uuid = ctools_uuid_generate();
1069
  }
1070 85ad3d82 Assos Assos
  drupal_write_record('panels_display', $display, $update);
1071
1072
  $pids = array();
1073
  if ($update) {
1074 64156087 Assos Assos
    // Get a list of all panes currently in the database for this display so we
1075
    // can know if there are panes that need to be deleted. (i.e, aren't
1076
    // currently in our list of panes).
1077
    $result = db_query(
1078
      "SELECT pid FROM {panels_pane} WHERE did = :did",
1079
      array(':did' => $display->did)
1080
    );
1081 85ad3d82 Assos Assos
    foreach ($result as $pane) {
1082
      $pids[$pane->pid] = $pane->pid;
1083
    }
1084
  }
1085
1086 64156087 Assos Assos
  // Update all the panes.
1087 85ad3d82 Assos Assos
  ctools_include('plugins', 'panels');
1088
  ctools_include('content');
1089
1090
  foreach ($display->panels as $id => $panes) {
1091
    $position = 0;
1092
    $new_panes = array();
1093
    foreach ((array) $panes as $pid) {
1094
      if (!isset($display->content[$pid])) {
1095
        continue;
1096
      }
1097
      $pane = $display->content[$pid];
1098
      $type = ctools_get_content_type($pane->type);
1099
1100
      $pane->position = $position++;
1101
      $pane->did = $display->did;
1102
1103
      $old_pid = $pane->pid;
1104 5a7e6170 Florent Torregrosa
1105
      if (empty($pane->uuid) || !ctools_uuid_is_valid($pane->uuid)) {
1106
        $pane->uuid = ctools_uuid_generate();
1107
      }
1108
1109 85ad3d82 Assos Assos
      drupal_write_record('panels_pane', $pane, is_numeric($pid) ? array('pid') : array());
1110
1111 5a7e6170 Florent Torregrosa
      // Allow other modules to take action after a pane is saved.
1112
      if ($pane->pid == $old_pid) {
1113
        module_invoke_all('panels_pane_update', $pane);
1114
      }
1115
      else {
1116
        module_invoke_all('panels_pane_insert', $pane);
1117
      }
1118
1119 85ad3d82 Assos Assos
      if ($pane->pid != $old_pid) {
1120 5a7e6170 Florent Torregrosa
        // Remove the old new-* entry from the displays content.
1121
        unset($display->content[$pid]);
1122
1123 64156087 Assos Assos
        // Put it back so our pids and positions can be used.
1124 85ad3d82 Assos Assos
        $display->content[$pane->pid] = $pane;
1125
1126
        // If the title pane was one of our panes that just got its ID changed,
1127
        // we need to change it in the database, too.
1128
        if (isset($display->title_pane) && $display->title_pane == $old_pid) {
1129
          $display->title_pane = $pane->pid;
1130
          // Do a simple update query to write it so we don't have to rewrite
1131
          // the whole record. We can't just save writing the whole record here
1132
          // because it was needed to get the did. Chicken, egg, more chicken.
1133
          db_update('panels_display')
1134
            ->fields(array(
1135 64156087 Assos Assos
              'title_pane' => $pane->pid,
1136 85ad3d82 Assos Assos
            ))
1137
            ->condition('did', $display->did)
1138
            ->execute();
1139
        }
1140
      }
1141
1142
      // re-add this to the list of content for this panel.
1143
      $new_panes[] = $pane->pid;
1144
1145
      // Remove this from the list of panes scheduled for deletion.
1146
      if (isset($pids[$pane->pid])) {
1147
        unset($pids[$pane->pid]);
1148
      }
1149
    }
1150
1151
    $display->panels[$id] = $new_panes;
1152
  }
1153
  if (!empty($pids)) {
1154 5a7e6170 Florent Torregrosa
    // Allow other modules to take action before a panes are deleted.
1155
    module_invoke_all('panels_pane_delete', $pids);
1156 85ad3d82 Assos Assos
    db_delete('panels_pane')->condition('pid', $pids)->execute();
1157
  }
1158
1159
  // Clear any cached content for this display.
1160
  panels_clear_cached_content($display);
1161
1162
  // Allow other modules to take action when a display is saved.
1163
  module_invoke_all('panels_display_save', $display);
1164
1165 64156087 Assos Assos
  // Log the change to watchdog, using the same style as node.module.
1166 85ad3d82 Assos Assos
  $watchdog_args = array('%did' => $display->did);
1167
  if (!empty($display->title)) {
1168
    $watchdog_args['%title'] = $display->title;
1169
    watchdog('content', 'Panels: saved display "%title" with display id %did', $watchdog_args, WATCHDOG_NOTICE);
1170
  }
1171
  else {
1172
    watchdog('content', 'Panels: saved display with id %did', $watchdog_args, WATCHDOG_NOTICE);
1173
  }
1174
1175 64156087 Assos Assos
  // To be nice, even though we have a reference.
1176 85ad3d82 Assos Assos
  return $display;
1177
}
1178
1179
/**
1180
 * Delete a display.
1181
 */
1182
function panels_delete_display($display) {
1183
  if (is_object($display)) {
1184
    $did = $display->did;
1185
  }
1186
  else {
1187
    $did = $display;
1188
  }
1189 5a7e6170 Florent Torregrosa
  module_invoke_all('panels_delete_display', $did);
1190 85ad3d82 Assos Assos
  db_delete('panels_display')->condition('did', $did)->execute();
1191
  db_delete('panels_pane')->condition('did', $did)->execute();
1192
}
1193
1194
/**
1195
 * Exports the provided display into portable code.
1196
 *
1197
 * This function is primarily intended as a mechanism for cloning displays.
1198
 * It generates an exact replica (in code) of the provided $display, with
1199 5a7e6170 Florent Torregrosa
 * the exception that it replaces all ids (dids and pids) with place-holder
1200
 * values (consisting of the display or pane's uuid, with a 'new-' prefix).
1201
 *
1202
 * Only once panels_save_display() is called on the code version of $display
1203
 * will the exported display be written to the database and permanently saved.
1204 85ad3d82 Assos Assos
 *
1205 64156087 Assos Assos
 * @param object $display
1206
 *   This export function does no loading of additional data about the provided
1207
 *   display. Consequently, the caller should make sure that all the desired
1208
 *   data has been loaded into the $display before calling this function.
1209 85ad3d82 Assos Assos
 * @param string $prefix
1210 64156087 Assos Assos
 *   A string prefix that is prepended to each line of exported code. This is
1211
 *   primarily used for prepending a double space when exporting so that the
1212
 *   code indents and lines up nicely.
1213 85ad3d82 Assos Assos
 *
1214
 * @return string $output
1215 64156087 Assos Assos
 *   The passed-in $display expressed as code, ready to be imported. Import by
1216
 *   running eval($output) in the caller function; doing so will create a new
1217
 *   $display variable with all the exported values. Note that if you have
1218
 *   already defined a $display variable in the same scope as where you eval(),
1219
 *   your existing $display variable WILL be overwritten.
1220
 *
1221
 * @see panels_page_export() or _panels_page_fetch_display() for samples.
1222
 *
1223
 * @ingroup mainapi
1224 85ad3d82 Assos Assos
 */
1225
function panels_export_display($display, $prefix = '') {
1226
  ctools_include('export');
1227 5a7e6170 Florent Torregrosa
  if (empty($display->uuid) || !ctools_uuid_is_valid($display->uuid)) {
1228
    $display->uuid = ctools_uuid_generate();
1229
  }
1230
  $display->did = 'new-' . $display->uuid;
1231 85ad3d82 Assos Assos
  $output = ctools_export_object('panels_display', $display, $prefix);
1232
1233
  // Initialize empty properties.
1234
  $output .= $prefix . '$display->content = array()' . ";\n";
1235
  $output .= $prefix . '$display->panels = array()' . ";\n";
1236
  $panels = array();
1237
1238
  $title_pid = 0;
1239
  if (!empty($display->content)) {
1240
    $region_counters = array();
1241
    foreach ($display->content as $pane) {
1242 5a7e6170 Florent Torregrosa
1243
      if (!isset($pane->uuid) || !ctools_uuid_is_valid($pane->uuid)) {
1244
        $pane->uuid = ctools_uuid_generate();
1245
      }
1246
      $pid = 'new-' . $pane->uuid;
1247
1248 85ad3d82 Assos Assos
      if ($pane->pid == $display->title_pane) {
1249
        $title_pid = $pid;
1250
      }
1251
      $pane->pid = $pid;
1252 136a805a Assos Assos
      $output .= ctools_export_object('panels_pane', $pane, $prefix);
1253
      $output .= $prefix . '$display->content[\'' . $pane->pid . '\'] = $pane' . ";\n";
1254 85ad3d82 Assos Assos
      if (!isset($region_counters[$pane->panel])) {
1255
        $region_counters[$pane->panel] = 0;
1256
      }
1257 64156087 Assos Assos
      $output .= $prefix . '$display->panels[\'' . $pane->panel . '\'][' . $region_counters[$pane->panel]++ . '] = \'' . $pane->pid . "';\n";
1258 85ad3d82 Assos Assos
    }
1259
  }
1260
  $output .= $prefix . '$display->hide_title = ';
1261
  switch ($display->hide_title) {
1262
    case PANELS_TITLE_FIXED:
1263
      $output .= 'PANELS_TITLE_FIXED';
1264
      break;
1265 64156087 Assos Assos
1266 85ad3d82 Assos Assos
    case PANELS_TITLE_NONE:
1267
      $output .= 'PANELS_TITLE_NONE';
1268
      break;
1269 64156087 Assos Assos
1270 85ad3d82 Assos Assos
    case PANELS_TITLE_PANE:
1271
      $output .= 'PANELS_TITLE_PANE';
1272
      break;
1273
  }
1274
  $output .= ";\n";
1275
1276
  $output .= $prefix . '$display->title_pane =' . " '$title_pid';\n";
1277
  return $output;
1278
}
1279
1280
/**
1281 64156087 Assos Assos
 * Panels Render Display.
1282
 *
1283 85ad3d82 Assos Assos
 * Render a display by loading the content into an appropriate
1284
 * array and then passing through to panels_render_layout.
1285
 *
1286
 * if $incoming_content is NULL, default content will be applied. Use
1287
 * an empty string to indicate no content.
1288 64156087 Assos Assos
 *
1289 85ad3d82 Assos Assos
 * @ingroup hook_invocations
1290
 */
1291
function panels_render_display(&$display, $renderer = NULL) {
1292
  ctools_include('plugins', 'panels');
1293
  ctools_include('context');
1294
1295
  if (!empty($display->context)) {
1296
    if ($form_context = ctools_context_get_form($display->context)) {
1297
      $form_context->form['#theme'] = 'panels_render_display_form';
1298 5a7e6170 Florent Torregrosa
      if (empty($form_context->form['#theme_wrappers']) || !in_array('form', $form_context->form['#theme_wrappers'])) {
1299 64156087 Assos Assos
        $form_context->form['#theme_wrappers'][] = 'form';
1300 5a7e6170 Florent Torregrosa
      }
1301 85ad3d82 Assos Assos
      $form_context->form['#display'] = &$display;
1302
      return $form_context->form;
1303
    }
1304
  }
1305
  return $display->render($renderer);
1306
}
1307
1308
/**
1309
 * Theme function to render our panel as a form.
1310
 *
1311
 * When rendering a display as a form, the entire display needs to be
1312
 * inside the <form> tag so that the form can be spread across the
1313
 * panes. This sets up the form system to be the main caller and we
1314
 * then operate as a theme function of the form.
1315
 */
1316
function theme_panels_render_display_form($vars) {
1317 5a7e6170 Florent Torregrosa
  return $vars['element']['#display']->render();
1318 85ad3d82 Assos Assos
}
1319
1320 64156087 Assos Assos
/**
1321
 * Panels layout icon function.
1322
 */
1323 85ad3d82 Assos Assos
function panels_print_layout_icon($id, $layout, $title = NULL) {
1324
  ctools_add_css('panels_admin', 'panels');
1325
  $file = $layout['path'] . '/' . $layout['icon'];
1326 64156087 Assos Assos
  return theme(
1327
    'panels_layout_icon',
1328
    array(
1329
      'id' => $id,
1330
      'image' => theme(
1331
        'image',
1332
        array(
1333
          'path' => $file,
1334
          'alt' => strip_tags($layout['title']),
1335
          'title' => strip_tags($layout['description']),
1336
        )
1337
      ),
1338
      'title' => $title,
1339
    )
1340
  );
1341 85ad3d82 Assos Assos
}
1342
1343
/**
1344 64156087 Assos Assos
 * Theme the layout icon image.
1345
 *
1346 85ad3d82 Assos Assos
 * @todo move to theme.inc
1347
 */
1348
function theme_panels_layout_icon($vars) {
1349
  $id = $vars['id'];
1350
  $image = $vars['image'];
1351
  $title = $vars['title'];
1352
1353
  $output = '<div class="layout-icon">';
1354
  $output .= $image;
1355
  if ($title) {
1356
    $output .= '<div class="caption">' . $title . '</div>';
1357
  }
1358
  $output .= '</div>';
1359
  return $output;
1360
}
1361
1362
/**
1363 64156087 Assos Assos
 * Theme the layout link image.
1364
 *
1365 85ad3d82 Assos Assos
 * @layout
1366
 *
1367
 * @todo Why isn't this a template at this point?
1368
 * @todo Why does this take 4 arguments but only makes use of two?
1369
 */
1370
function theme_panels_layout_link($vars) {
1371 64156087 Assos Assos
  $output = '<div class="' . implode(' ', $vars['class']) . '">';
1372 85ad3d82 Assos Assos
  $output .= $vars['image'];
1373
  $output .= '<div>' . $vars['title'] . '</div>';
1374
  $output .= '</div>';
1375
  return $output;
1376
}
1377
1378
/**
1379
 * Print the layout link. Sends out to a theme function.
1380 64156087 Assos Assos
 *
1381 85ad3d82 Assos Assos
 * @layout
1382
 */
1383
function panels_print_layout_link($id, $layout, $link, $options = array(), $current_layout = FALSE) {
1384
  if (isset($options['query']['q'])) {
1385
    unset($options['query']['q']);
1386
  }
1387
1388 64156087 Assos Assos
  // Setup classes for layout link, including current-layout information.
1389 85ad3d82 Assos Assos
  $class = array('layout-link');
1390
  if ($current_layout == $id) {
1391
    $options['attributes']['class'][] = 'current-layout-link';
1392
    $class[] = 'current-layout';
1393
  }
1394
1395
  ctools_add_css('panels_admin', 'panels');
1396
  $file = $layout['path'] . '/' . $layout['icon'];
1397 64156087 Assos Assos
  $image = l(
1398
    theme('image', array('path' => $file)),
1399
    $link,
1400
    array('html' => TRUE) + $options
1401
  );
1402 85ad3d82 Assos Assos
  $title = l($layout['title'], $link, $options);
1403 64156087 Assos Assos
  return theme(
1404
    'panels_layout_link',
1405
    array(
1406
      'title' => $title,
1407
      'image' => $image,
1408
      'class' => $class,
1409
    )
1410
  );
1411 85ad3d82 Assos Assos
}
1412
1413
1414
/**
1415 64156087 Assos Assos
 * Panels Get legacy state.
1416
 *
1417 85ad3d82 Assos Assos
 * Gateway to the PanelsLegacyState class/object, which does all legacy state
1418
 * checks and provides information about the cause of legacy states as needed.
1419
 *
1420
 * @return PanelsLegacyState $legacy
1421 64156087 Assos Assos
 *   Returns a legacy panels state.
1422 85ad3d82 Assos Assos
 */
1423
function panels_get_legacy_state() {
1424
  static $legacy = NULL;
1425
  if (!isset($legacy)) {
1426
    ctools_include('legacy', 'panels');
1427
    $legacy = new PanelsLegacyState();
1428
  }
1429
  return $legacy;
1430
}
1431
1432
/**
1433
 * Get the display that is currently being rendered as a page.
1434
 *
1435
 * Unlike in previous versions of this, this only returns the display,
1436
 * not the page itself, because there are a number of different ways
1437
 * to get to this point. It is hoped that the page data isn't needed
1438
 * at this point. If it turns out there is, we will do something else to
1439
 * get that functionality.
1440
 */
1441
function panels_get_current_page_display($change = NULL) {
1442
  static $display = NULL;
1443
  if ($change) {
1444
    $display = $change;
1445
  }
1446
1447
  return $display;
1448
}
1449
1450
/**
1451
 * Clean up the panel pane variables for the template.
1452
 */
1453
function template_preprocess_panels_pane(&$vars) {
1454
  $content = &$vars['content'];
1455
1456
  $vars['contextual_links'] = array();
1457
  $vars['classes_array'] = array();
1458
  $vars['admin_links'] = '';
1459
1460
  if (module_exists('contextual') && user_access('access contextual links')) {
1461
    $links = array();
1462
    // These are specified by the content.
1463
    if (!empty($content->admin_links)) {
1464
      $links += $content->admin_links;
1465
    }
1466
1467
    // Take any that may have been in the render array we were given and
1468
    // move them up so they appear outside the pane properly.
1469
    if (is_array($content->content) && isset($content->content['#contextual_links'])) {
1470
      $element = array(
1471
        '#type' => 'contextual_links',
1472
        '#contextual_links' => $content->content['#contextual_links'],
1473
      );
1474
      unset($content->content['#contextual_links']);
1475
1476 64156087 Assos Assos
      // Add content to $element array.
1477 85ad3d82 Assos Assos
      if (is_array($content->content)) {
1478
        $element['#element'] = $content->content;
1479
      }
1480
1481
      $element = contextual_pre_render_links($element);
1482 64156087 Assos Assos
      if (!empty($element['#links'])) {
1483 5a7e6170 Florent Torregrosa
        $links += $element['#links'];
1484
      }
1485 85ad3d82 Assos Assos
    }
1486
1487
    if ($links) {
1488
      $build = array(
1489
        '#prefix' => '<div class="contextual-links-wrapper">',
1490
        '#suffix' => '</div>',
1491
        '#theme' => 'links__contextual',
1492
        '#links' => $links,
1493
        '#attributes' => array('class' => array('contextual-links')),
1494
        '#attached' => array(
1495
          'library' => array(array('contextual', 'contextual-links')),
1496
        ),
1497
      );
1498
      $vars['classes_array'][] = 'contextual-links-region';
1499
      $vars['admin_links'] = drupal_render($build);
1500
    }
1501
  }
1502
1503 64156087 Assos Assos
  // Basic classes.
1504 85ad3d82 Assos Assos
  $vars['classes_array'][] = 'panel-pane';
1505
  $vars['id'] = '';
1506
1507 64156087 Assos Assos
  // Add some usable classes based on type/subtype.
1508 85ad3d82 Assos Assos
  ctools_include('cleanstring');
1509 64156087 Assos Assos
  $type_class = $content->type ? 'pane-' . ctools_cleanstring($content->type, array('lower case' => TRUE)) : '';
1510
  $subtype_class = $content->subtype ? 'pane-' . ctools_cleanstring($content->subtype, array('lower case' => TRUE)) : '';
1511 85ad3d82 Assos Assos
1512
  // Sometimes type and subtype are the same. Avoid redundant classes.
1513
  $vars['classes_array'][] = $type_class;
1514
  if ($type_class != $subtype_class) {
1515
    $vars['classes_array'][] = $subtype_class;
1516
  }
1517
1518
  // Add id and custom class if sent in.
1519
  if (!empty($content->content)) {
1520
    if (!empty($content->css_id)) {
1521
      $vars['id'] = ' id="' . $content->css_id . '"';
1522
    }
1523
    if (!empty($content->css_class)) {
1524
      $vars['classes_array'][] = $content->css_class;
1525
    }
1526
  }
1527
1528
  // Set up some placeholders for constructing template file names.
1529
  $base = 'panels_pane';
1530
  $delimiter = '__';
1531
1532
  // Add template file suggestion for content type and sub-type.
1533
  $vars['theme_hook_suggestions'][] = $base . $delimiter . $content->type;
1534 5a7e6170 Florent Torregrosa
  $vars['theme_hook_suggestions'][] = $base . $delimiter . strtr(ctools_cleanstring($content->type, array('lower case' => TRUE)), '-', '_') . $delimiter . strtr(ctools_cleanstring($content->subtype, array('lower case' => TRUE)), '-', '_');
1535 85ad3d82 Assos Assos
1536
  $vars['pane_prefix'] = !empty($content->pane_prefix) ? $content->pane_prefix : '';
1537
  $vars['pane_suffix'] = !empty($content->pane_suffix) ? $content->pane_suffix : '';
1538
1539
  $vars['title'] = !empty($content->title) ? $content->title : '';
1540 136a805a Assos Assos
  $vars['title_heading'] = !empty($content->title_heading) ? $content->title_heading : variable_get('override_title_heading', 'h2');
1541 85ad3d82 Assos Assos
  $vars['title_attributes_array']['class'][] = 'pane-title';
1542
1543
  $vars['feeds'] = !empty($content->feeds) ? implode(' ', $content->feeds) : '';
1544
1545
  $vars['links'] = !empty($content->links) ? theme('links', array('links' => $content->links)) : '';
1546
  $vars['more'] = '';
1547
  if (!empty($content->more)) {
1548
    if (empty($content->more['title'])) {
1549
      $content->more['title'] = t('more');
1550
    }
1551
    $vars['more'] = l($content->more['title'], $content->more['href'], $content->more);
1552
  }
1553
1554 64156087 Assos Assos
  if (!empty($content->attributes)) {
1555
    $vars['attributes_array'] = array_merge($vars['attributes_array'], $content->attributes);
1556
  }
1557
1558 85ad3d82 Assos Assos
  $vars['content'] = !empty($content->content) ? $content->content : '';
1559
1560
}
1561
1562
/**
1563
 * Route Panels' AJAX calls to the correct object.
1564
 *
1565
 * Panels' AJAX is controlled mostly by renderer objects. This menu callback
1566
 * accepts the incoming request, figures out which object should handle the
1567
 * request, and attempts to route it. If no object can be found, the default
1568
 * Panels editor object is used.
1569
 *
1570
 * Calls are routed via the ajax_* method space. For example, if visiting
1571
 * panels/ajax/add-pane then $renderer::ajax_add_pane() will be called.
1572
 * This means commands can be added without having to create new callbacks.
1573
 *
1574
 * The first argument *must always* be the cache key so that a cache object
1575
 * can be passed through. Other arguments will be passed through untouched
1576
 * so that the method can do whatever it needs to do.
1577
 */
1578
function panels_ajax_router() {
1579
  $args = func_get_args();
1580
  if (count($args) < 3) {
1581
    return MENU_NOT_FOUND;
1582
  }
1583
1584
  ctools_include('display-edit', 'panels');
1585
  ctools_include('plugins', 'panels');
1586
  ctools_include('ajax');
1587
  ctools_include('modal');
1588
  ctools_include('context');
1589
  ctools_include('content');
1590
1591
  $plugin_name = array_shift($args);
1592
  $method = array_shift($args);
1593
  $cache_key = array_shift($args);
1594
1595
  $plugin = panels_get_display_renderer($plugin_name);
1596
  if (!$plugin) {
1597
    // This is the default renderer for handling AJAX commands.
1598
    $plugin = panels_get_display_renderer('editor');
1599
  }
1600
1601
  $cache = panels_edit_cache_get($cache_key);
1602
  if (empty($cache)) {
1603
    return MENU_ACCESS_DENIED;
1604
  }
1605
1606
  $renderer = panels_get_renderer_handler($plugin, $cache->display);
1607
  if (!$renderer) {
1608
    return MENU_ACCESS_DENIED;
1609
  }
1610
1611
  $method = 'ajax_' . str_replace('-', '_', $method);
1612
  if (!method_exists($renderer, $method)) {
1613
    return MENU_NOT_FOUND;
1614
  }
1615
1616
  $renderer->cache = &$cache;
1617
  ctools_include('cleanstring');
1618
  $renderer->clean_key = ctools_cleanstring($cache_key);
1619
1620 136a805a Assos Assos
  $op = $renderer->get_panels_storage_op_for_ajax($method);
1621
  if (!$cache->display->access($op)) {
1622
    return MENU_ACCESS_DENIED;
1623
  }
1624
1625 85ad3d82 Assos Assos
  $output = call_user_func_array(array($renderer, $method), $args);
1626
1627
  if (empty($output) && !empty($renderer->commands)) {
1628
    return array(
1629
      '#type' => 'ajax',
1630
      '#commands' => $renderer->commands,
1631
    );
1632
  }
1633
  else {
1634
    return $output;
1635
  }
1636
}
1637
1638 64156087 Assos Assos
/**
1639
 * Panels caching functions and callbacks.
1640
 *
1641
 * When editing displays and the like, Panels has a caching system that relies
1642
 * on a callback to determine where to get the actual cache.
1643
 *
1644
 * @todo This system needs to be better documented so that it can be better used.
1645
 */
1646 85ad3d82 Assos Assos
1647
/**
1648
 * Get an object from cache.
1649
 */
1650
function panels_cache_get($obj, $did, $skip_cache = FALSE) {
1651
  ctools_include('object-cache');
1652 64156087 Assos Assos
  // We often store contexts in cache, so let's just make sure we can load them.
1653 85ad3d82 Assos Assos
  ctools_include('context');
1654
  return ctools_object_cache_get($obj, 'panels_display:' . $did, $skip_cache);
1655
}
1656
1657
/**
1658
 * Save the edited object into the cache.
1659
 */
1660
function panels_cache_set($obj, $did, $cache) {
1661
  ctools_include('object-cache');
1662
  return ctools_object_cache_set($obj, 'panels_display:' . $did, $cache);
1663
}
1664
1665
/**
1666
 * Clear a object from the cache; used if the editing is aborted.
1667
 */
1668
function panels_cache_clear($obj, $did) {
1669
  ctools_include('object-cache');
1670
  return ctools_object_cache_clear($obj, 'panels_display:' . $did);
1671
}
1672
1673
/**
1674
 * Create the default cache for editing panel displays.
1675
 *
1676
 * If an application is using the Panels display editor without having
1677
 * specified a cache key, this method can be used to create the default
1678
 * cache.
1679
 */
1680
function panels_edit_cache_get_default(&$display, $content_types = NULL, $title = FALSE) {
1681
  if (empty($content_types)) {
1682
    $content_types = ctools_content_get_available_types();
1683
  }
1684
1685
  $display->cache_key = $display->did;
1686
  panels_cache_clear('display', $display->did);
1687
1688
  $cache = new stdClass();
1689
  $cache->display = &$display;
1690
  $cache->content_types = $content_types;
1691
  $cache->display_title = $title;
1692
1693
  panels_edit_cache_set($cache);
1694
  return $cache;
1695
}
1696
1697
/**
1698 64156087 Assos Assos
 * Panels Editor Cache Get.
1699
 *
1700 85ad3d82 Assos Assos
 * Method to allow modules to provide their own caching mechanism for the
1701
 * display editor.
1702
 */
1703
function panels_edit_cache_get($cache_key) {
1704
  if (strpos($cache_key, ':') !== FALSE) {
1705
    list($module, $argument) = explode(':', $cache_key, 2);
1706
    return module_invoke($module, 'panels_cache_get', $argument);
1707
  }
1708
1709 64156087 Assos Assos
  // Fall back to our normal method.
1710 85ad3d82 Assos Assos
  return panels_cache_get('display', $cache_key);
1711
}
1712
1713
/**
1714 64156087 Assos Assos
 * Panels Editor Cache Set.
1715
 *
1716 85ad3d82 Assos Assos
 * Method to allow modules to provide their own caching mechanism for the
1717
 * display editor.
1718
 */
1719
function panels_edit_cache_set($cache) {
1720
  $cache_key = $cache->display->cache_key;
1721
  if (strpos($cache_key, ':') !== FALSE) {
1722
    list($module, $argument) = explode(':', $cache_key, 2);
1723
    return module_invoke($module, 'panels_cache_set', $argument, $cache);
1724
  }
1725
1726 64156087 Assos Assos
  // Fall back to our normal method.
1727 85ad3d82 Assos Assos
  return panels_cache_set('display', $cache_key, $cache);
1728
}
1729
1730
/**
1731 64156087 Assos Assos
 * Panels Editor Cache Save.
1732
 *
1733 85ad3d82 Assos Assos
 * Method to allow modules to provide their own mechanism to write the
1734
 * cache used in the display editor.
1735
 */
1736
function panels_edit_cache_save($cache) {
1737
  $cache_key = $cache->display->cache_key;
1738
  if (strpos($cache_key, ':') !== FALSE) {
1739
    list($module, $argument) = explode(':', $cache_key, 2);
1740
    if (function_exists($module . '_panels_cache_save')) {
1741
      return module_invoke($module, 'panels_cache_save', $argument, $cache);
1742
    }
1743
  }
1744
1745 64156087 Assos Assos
  // Fall back to our normal method.
1746 85ad3d82 Assos Assos
  return panels_save_display($cache->display);
1747
}
1748
1749
/**
1750 64156087 Assos Assos
 * Panels Editor Cache Clear.
1751
 *
1752 85ad3d82 Assos Assos
 * Method to allow modules to provide their own mechanism to clear the
1753
 * cache used in the display editor.
1754
 */
1755
function panels_edit_cache_clear($cache) {
1756
  $cache_key = $cache->display->cache_key;
1757
  if (strpos($cache_key, ':') !== FALSE) {
1758
    list($module, $argument) = explode(':', $cache_key, 2);
1759
    if (function_exists($module . '_panels_cache_clear')) {
1760
      return module_invoke($module, 'panels_cache_clear', $argument, $cache);
1761
    }
1762
  }
1763
1764 64156087 Assos Assos
  // Fall back to our normal method.
1765 85ad3d82 Assos Assos
  return panels_cache_clear('display', $cache_key);
1766
}
1767
1768
/**
1769
 * Method to allow modules to provide a mechanism to break locks.
1770
 */
1771
function panels_edit_cache_break_lock($cache) {
1772
  if (empty($cache->locked)) {
1773
    return;
1774
  }
1775
1776
  $cache_key = $cache->display->cache_key;
1777
  if (strpos($cache_key, ':') !== FALSE) {
1778
    list($module, $argument) = explode(':', $cache_key, 2);
1779
    if (function_exists($module . '_panels_cache_break_lock')) {
1780
      return module_invoke($module, 'panels_cache_break_lock', $argument, $cache);
1781
    }
1782
  }
1783
1784
  // Normal panel display editing has no locks, so we do nothing if there is
1785
  // no fallback.
1786
}
1787
1788 64156087 Assos Assos
/**
1789
 * Callbacks on behalf of the panel_context plugin.
1790
 *
1791
 * The panel_context plugin lets Panels be used in page manager. These
1792
 * callbacks allow the display editing system to use the page manager
1793
 * cache rather than the default display cache. They are routed by the cache
1794
 * key via panels_edit_cache_* functions.
1795
 */
1796 85ad3d82 Assos Assos
1797
/**
1798
 * Get display edit cache on behalf of panel context.
1799
 *
1800
 * The key is the second half of the key in this form:
1801 5a7e6170 Florent Torregrosa
 * panel_context:TASK_NAME::HANDLER_NAME::args::url;
1802 85ad3d82 Assos Assos
 */
1803
function panel_context_panels_cache_get($key) {
1804
  ctools_include('common', 'panels');
1805
  ctools_include('context');
1806
  ctools_include('context-task-handler');
1807 64156087 Assos Assos
  // This loads the panel context inc even if we don't use the plugin.
1808 85ad3d82 Assos Assos
  $plugin = page_manager_get_task_handler('panel_context');
1809
1810 5a7e6170 Florent Torregrosa
  list($task_name, $handler_name, $args, $q) = explode('::', $key, 4);
1811 85ad3d82 Assos Assos
  $page = page_manager_get_page_cache($task_name);
1812
  if (isset($page->display_cache[$handler_name])) {
1813
    return $page->display_cache[$handler_name];
1814
  }
1815
1816
  if ($handler_name) {
1817
    $handler = &$page->handlers[$handler_name];
1818
  }
1819
  else {
1820
    $handler = &$page->new_handler;
1821
  }
1822
  $cache = new stdClass();
1823
1824 5a7e6170 Florent Torregrosa
  $task = page_manager_get_task($page->task_id);
1825
  $arguments = array();
1826
  if ($args) {
1827
    $arguments = explode('\\', $args);
1828
    $contexts = ctools_context_handler_get_task_contexts($task, $page->subtask, $arguments);
1829
    $contexts = ctools_context_handler_get_handler_contexts($contexts, $handler);
1830
  }
1831
  else {
1832
    $contexts = ctools_context_handler_get_all_contexts($page->task, $page->subtask, $handler);
1833
  }
1834
1835 85ad3d82 Assos Assos
  $cache->display = &panels_panel_context_get_display($handler);
1836 5a7e6170 Florent Torregrosa
  $cache->display->context = $contexts;
1837 85ad3d82 Assos Assos
  $cache->display->cache_key = 'panel_context:' . $key;
1838
  $cache->content_types = panels_common_get_allowed_types('panels_page', $cache->display->context);
1839
  $cache->display_title = TRUE;
1840
  $cache->locked = $page->locked;
1841
1842
  return $cache;
1843
}
1844
1845
/**
1846
 * Get the Page Manager cache for the panel_context plugin.
1847
 */
1848
function _panel_context_panels_cache_get_page_cache($key, $cache) {
1849 5a7e6170 Florent Torregrosa
  list($task_name, $handler_name, $args, $q) = explode('::', $key, 4);
1850 85ad3d82 Assos Assos
  $page = page_manager_get_page_cache($task_name);
1851
  $page->display_cache[$handler_name] = $cache;
1852
  if ($handler_name) {
1853
    $page->handlers[$handler_name]->conf['display'] = $cache->display;
1854
    $page->handler_info[$handler_name]['changed'] |= PAGE_MANAGER_CHANGED_CACHED;
1855
  }
1856
  else {
1857
    $page->new_handler->conf['display'] = $cache->display;
1858
  }
1859
1860
  return $page;
1861
}
1862
1863
/**
1864
 * Store a display edit in progress in the page cache.
1865
 */
1866
function panel_context_panels_cache_set($key, $cache) {
1867
  $page = _panel_context_panels_cache_get_page_cache($key, $cache);
1868
  page_manager_set_page_cache($page);
1869
}
1870
1871
/**
1872
 * Save all changes made to a display using the Page Manager page cache.
1873
 */
1874
function panel_context_panels_cache_clear($key, $cache) {
1875
  $page = _panel_context_panels_cache_get_page_cache($key, $cache);
1876
  page_manager_clear_page_cache($page->task_name);
1877
}
1878
1879
/**
1880
 * Save all changes made to a display using the Page Manager page cache.
1881
 */
1882
function panel_context_panels_cache_save($key, $cache) {
1883
  $page = _panel_context_panels_cache_get_page_cache($key, $cache);
1884
  page_manager_save_page_cache($page);
1885
}
1886
1887
/**
1888
 * Break the lock on a page manager page.
1889
 */
1890
function panel_context_panels_cache_break_lock($key, $cache) {
1891
  $page = _panel_context_panels_cache_get_page_cache($key, $cache);
1892
  ctools_object_cache_clear_all('page_manager_page', $page->task_name);
1893
}
1894
1895 64156087 Assos Assos
/**
1896
 * Callbacks on behalf of the panels page wizards.
1897
 *
1898
 * The page wizards are a pluggable set of 'wizards' to make it easy to create
1899
 * specific types of pages based upon whatever someone felt like putting
1900
 * together. Since they will very often have content editing, we provide
1901
 * a generic mechanism to allow them to store their editing cache in the
1902
 * wizard cache.
1903
 *
1904
 * For them to use this mechanism, they just need to use:
1905
 * $cache = panels_edit_cache_get('panels_page_wizard:' . $plugin['name']);.
1906
 */
1907 85ad3d82 Assos Assos
1908
/**
1909 64156087 Assos Assos
 * Get display edit cache for the panels mini export UI.
1910 85ad3d82 Assos Assos
 *
1911
 * The key is the second half of the key in this form:
1912
 * panels_page_wizard:TASK_NAME:HANDLER_NAME;
1913
 */
1914
function panels_page_wizard_panels_cache_get($key) {
1915
  ctools_include('page-wizard');
1916
  ctools_include('context');
1917
  $wizard_cache = page_manager_get_wizard_cache($key);
1918
  if (isset($wizard_cache->display_cache)) {
1919
    return $wizard_cache->display_cache;
1920
  }
1921
1922
  ctools_include('common', 'panels');
1923
  $cache = new stdClass();
1924
  $cache->display = $wizard_cache->display;
1925
  $cache->display->context = !empty($wizard_cache->context) ? $wizard_cache->context : array();
1926
  $cache->display->cache_key = 'panels_page_wizard:' . $key;
1927
  $cache->content_types = panels_common_get_allowed_types('panels_page', $cache->display->context);
1928
  $cache->display_title = TRUE;
1929
1930
  return $cache;
1931
}
1932
1933
/**
1934
 * Store a display edit in progress in the page cache.
1935
 */
1936
function panels_page_wizard_panels_cache_set($key, $cache) {
1937
  ctools_include('page-wizard');
1938
  $wizard_cache = page_manager_get_wizard_cache($key);
1939
  $wizard_cache->display_cache = $cache;
1940
  page_manager_set_wizard_cache($wizard_cache);
1941
}
1942
1943 2545992a Assos Assos
/**
1944
 * Implements hook_default_page_manager_handlers_alter().
1945
 *
1946
 * If a default Panels display has no storage type, set it.
1947
 */
1948
function panels_default_page_manager_handlers_alter(&$handlers) {
1949
  foreach ($handlers as &$handler) {
1950
    if ($handler->handler == 'panel_context') {
1951
      $display =& $handler->conf['display'];
1952
      if (empty($display->storage_type)) {
1953
        $display->storage_type = 'page_manager';
1954
        $display->storage_id = $handler->name;
1955
      }
1956
    }
1957
  }
1958
}
1959
1960
/**
1961
 * Implements hook_default_page_manager_pages_alter().
1962
 */
1963
function panels_default_page_manager_pages_alter(&$pages) {
1964
  foreach ($pages as &$page) {
1965
    panels_default_page_manager_handlers_alter($page->default_handlers);
1966
  }
1967
}
1968
1969 64156087 Assos Assos
/**
1970
 * General utility functions.
1971
 */
1972 85ad3d82 Assos Assos
1973
/**
1974
 * Perform a drupal_goto on a destination that may be an array like url().
1975
 */
1976
function panels_goto($destination) {
1977
  if (!is_array($destination)) {
1978
    return drupal_goto($destination);
1979
  }
1980
  else {
1981 64156087 Assos Assos
    // Prevent notices by adding defaults.
1982 85ad3d82 Assos Assos
    $destination += array(
1983
      'query' => NULL,
1984
      'fragment' => NULL,
1985
      'http_response_code' => NULL,
1986
    );
1987
1988 64156087 Assos Assos
    return drupal_goto(
1989
      $destination['path'],
1990
      $destination['query'],
1991
      $destination['fragment'],
1992
      $destination['http_response_code']
1993
    );
1994 85ad3d82 Assos Assos
  }
1995
}
1996
1997
1998
/**
1999 64156087 Assos Assos
 * For external use: Given a layout ID and $content array, return panel display.
2000 85ad3d82 Assos Assos
 *
2001
 * The content array is filled in based upon the content available in the
2002 64156087 Assos Assos
 * layout. If it's a two column with a content array defined like.
2003 85ad3d82 Assos Assos
 * @code
2004
 *   array(
2005
 *    'left' => t('Left side'),
2006
 *    'right' => t('Right side')
2007
 *  ),
2008
 *
2009
 * Then the $content array should be
2010
 * @code
2011
 * array(
2012
 *   'left' => $output_left,
2013
 *   'right' => $output_right,
2014
 * )
2015
 *
2016
 * The output within each panel region can be either a single rendered
2017
 * HTML string or an array of rendered HTML strings as though they were
2018
 * panes. They will simply be concatenated together without separators.
2019
 */
2020
function panels_print_layout($layout, $content, $meta = 'standard') {
2021
  ctools_include('plugins', 'panels');
2022
2023
  // Create a temporary display for this.
2024
  $display = panels_new_display();
2025
  $display->layout = is_array($layout) ? $layout['name'] : $layout;
2026
  $display->content = $content;
2027
2028 64156087 Assos Assos
  // Get our simple renderer.
2029 85ad3d82 Assos Assos
  $renderer = panels_get_renderer_handler('simple', $display);
2030
  $renderer->meta_location = $meta;
2031
2032
  return $renderer->render();
2033
}
2034
2035
/**
2036
 * Filter callback for array_filter to remove builders from a list of layouts.
2037
 */
2038
function _panels_builder_filter($layout) {
2039
  return empty($layout['builder']);
2040
}
2041
2042 e4c061ad Assos Assos
/**
2043
 * Implements hook_get_pane_links_alter().
2044
 */
2045
function panels_get_pane_links_alter(&$links, $pane, $content_type) {
2046 64156087 Assos Assos
  // Add links to the Panels pane dropdown menu.
2047
  if ($pane->type === "block") {
2048 e4c061ad Assos Assos
    $prefixed_name = $pane->subtype;
2049
2050 64156087 Assos Assos
    // Breakup the subtype string into parts.
2051 e4c061ad Assos Assos
    $exploded_subtype = explode('-', $pane->subtype);
2052
2053 64156087 Assos Assos
    // Get the first part of the string.
2054 e4c061ad Assos Assos
    $subtype_prefix = $exploded_subtype[0];
2055
2056 64156087 Assos Assos
    // Get the first part of the string and add a hyphen.
2057 e4c061ad Assos Assos
    $subtype_prefix_hyphen = $exploded_subtype[0] . '-';
2058
2059 64156087 Assos Assos
    // Remove the prefix block- to get the name.
2060
    $name_of_block = ltrim($prefixed_name, $subtype_prefix_hyphen);
2061 e4c061ad Assos Assos
2062 64156087 Assos Assos
    // Check for user added menus created at /admin/structure/menu/add
2063
    // menus of that type have a subtype that is prefixed with menu-menu-.
2064
    if (substr($prefixed_name, 0, 10) === "menu-menu-") {
2065
      // Remove the first prefix menu- from menu-menu- to get the name.
2066 e4c061ad Assos Assos
      $name_of_block = substr($prefixed_name, 5);
2067
2068
      $links['top'][] = array(
2069
        'title' => t('Edit block'),
2070
        'href' => url('admin/structure/block/manage/' . $subtype_prefix . '/' . $name_of_block . '/configure', array('absolute' => TRUE)),
2071
        'attributes' => array('target' => array('_blank')),
2072
      );
2073
2074
      $links['top'][] = array(
2075
        'title' => t('Edit menu links'),
2076
        'href' => url('admin/structure/menu/manage/' . $name_of_block, array('absolute' => TRUE)),
2077
        'attributes' => array('target' => array('_blank')),
2078
      );
2079
    }
2080
2081 64156087 Assos Assos
    // Check for module provided menu blocks like Devels or Features
2082
    // menus of that type have a subtype that is prefixed with menu-.
2083
    elseif (substr($prefixed_name, 0, 5) === "menu-") {
2084
      // Remove the first prefix menu- to get the name.
2085 e4c061ad Assos Assos
      $name_of_block = substr($prefixed_name, 5);
2086
2087
      $links['top'][] = array(
2088
        'title' => t('Edit block'),
2089
        'href' => url('admin/structure/block/manage/' . $subtype_prefix . '/' . $name_of_block . '/configure', array('absolute' => TRUE)),
2090
        'attributes' => array('target' => array('_blank')),
2091
      );
2092
2093
      $links['top'][] = array(
2094
        'title' => t('Edit menu links'),
2095
        'href' => url('admin/structure/menu/manage/' . $name_of_block, array('absolute' => TRUE)),
2096
        'attributes' => array('target' => array('_blank')),
2097
      );
2098
    }
2099
2100 64156087 Assos Assos
    // Check for system blocks with menu links.
2101
    elseif (substr($prefixed_name, 0, 7) === "system-") {
2102
      // Remove the first prefix system- to get the name.
2103 e4c061ad Assos Assos
      $name_of_block = substr($prefixed_name, 7);
2104
2105
      $names_of_system_menus = menu_list_system_menus();
2106
2107
      $links['top'][] = array(
2108
        'title' => t('Edit block'),
2109
        'href' => url('admin/structure/block/manage/' . $subtype_prefix . '/' . $name_of_block . '/configure', array('absolute' => TRUE)),
2110
        'attributes' => array('target' => array('_blank')),
2111
      );
2112
2113 64156087 Assos Assos
      if (array_key_exists($name_of_block, $names_of_system_menus)) {
2114 e4c061ad Assos Assos
        $links['top'][] = array(
2115
          'title' => t('Edit menu links'),
2116
          'href' => url('admin/structure/menu/manage/' . $name_of_block, array('absolute' => TRUE)),
2117
          'attributes' => array('target' => array('_blank')),
2118
        );
2119
      }
2120
    }
2121
2122 64156087 Assos Assos
    // For all other blocks without menus.
2123
    else {
2124 e4c061ad Assos Assos
      $links['top'][] = array(
2125
        'title' => t('Edit block'),
2126
        'href' => url('admin/structure/block/manage/' . $subtype_prefix . '/' . $name_of_block . '/configure', array('absolute' => TRUE)),
2127
        'attributes' => array('target' => array('_blank')),
2128
      );
2129
    }
2130
  }
2131
}
2132
2133 64156087 Assos Assos
/**
2134
 * Deprecated functions.
2135
 *
2136
 * Everything below this line will eventually go away.
2137
 */
2138 85ad3d82 Assos Assos
2139
/**
2140 64156087 Assos Assos
 * Panels path helper function.
2141 85ad3d82 Assos Assos
 */
2142
function panels_get_path($file, $base_path = FALSE, $module = 'panels') {
2143
  $output = $base_path ? base_path() : '';
2144
  return $output . drupal_get_path('module', $module) . '/' . $file;
2145
}
2146
2147
/**
2148 64156087 Assos Assos
 * Remove default sidebar related body classes and provide own css classes.
2149 85ad3d82 Assos Assos
 */
2150
function panels_preprocess_html(&$vars) {
2151
  $panel_body_css = &drupal_static('panel_body_css');
2152
  if (!empty($panel_body_css['body_classes_to_remove'])) {
2153 e4c061ad Assos Assos
    $classes_to_remove = array_filter(explode(' ', $panel_body_css['body_classes_to_remove']), 'strlen');
2154 85ad3d82 Assos Assos
    foreach ($vars['classes_array'] as $key => $css_class) {
2155
      if (in_array($css_class, $classes_to_remove)) {
2156
        unset($vars['classes_array'][$key]);
2157
      }
2158
    }
2159
  }
2160
  if (!empty($panel_body_css['body_classes_to_add'])) {
2161
    $vars['classes_array'][] = check_plain($panel_body_css['body_classes_to_add']);
2162
  }
2163
}