Projet

Général

Profil

Paste
Télécharger (62,2 ko) Statistiques
| Branche: | Révision:

root / drupal7 / sites / all / modules / panels / plugins / display_renderers / panels_renderer_editor.class.php @ 5a7e6170

1
<?php
2

    
3
/**
4
 * @file
5
 * Class file to control the main Panels editor.
6
 */
7

    
8
class panels_renderer_editor extends panels_renderer_standard {
9

    
10
  /**
11
   * An array of AJAX commands to return. If populated it will automatically
12
   * be used by the AJAX router.
13
   */
14
  var $commands = array();
15
  var $admin = TRUE;
16

    
17
  /**
18
   * Set to true if edit links (for panes and regions) should not be displayed.
19
   * This can be used for special edit modes such as layout change and layout
20
   * builder that do not actually have real content.
21
   */
22
  var $no_edit_links = FALSE;
23
  // -------------------------------------------------------------------------
24
  // Display edit rendering.
25

    
26
  function edit() {
27
    $form_state = array(
28
      'display' => &$this->display,
29
      'renderer' => &$this,
30
      'content_types' => $this->cache->content_types,
31
      'no_redirect' => TRUE,
32
      'display_title' => !empty($this->cache->display_title),
33
      'cache key' => $this->display->cache_key,
34
    );
35

    
36
    $output = drupal_build_form('panels_edit_display_form', $form_state);
37
    if (empty($form_state['executed']) || !empty($form_state['clicked_button']['preview'])) {
38
      return $output;
39
    }
40

    
41
    if (!empty($form_state['clicked_button']['#save-display'])) {
42
      drupal_set_message(t('Panel content has been updated.'));
43
      panels_save_display($this->display);
44
    }
45
    else {
46
      drupal_set_message(t('Your changes have been discarded.'));
47
    }
48

    
49
    panels_cache_clear('display', $this->display->did);
50
    return $this->display;
51
  }
52

    
53
  function add_meta() {
54
    parent::add_meta();
55
    if ($this->admin) {
56
      ctools_include('ajax');
57
      ctools_include('modal');
58
      ctools_modal_add_js();
59

    
60
      ctools_add_js('panels-base', 'panels');
61
      ctools_add_js('display_editor', 'panels');
62
      ctools_add_css('panels_dnd', 'panels');
63
      ctools_add_css('panels_admin', 'panels');
64
    }
65
  }
66

    
67
  function render() {
68
    // Pass through to normal rendering if not in admin mode.
69
    if (!$this->admin) {
70
      return parent::render();
71
    }
72

    
73
    $this->add_meta();
74

    
75
    $output = '<div class="panels-dnd" id="panels-dnd-main">';
76
    $output .= $this->render_layout();
77
    $output .= '</div>';
78

    
79
    return $output;
80
  }
81

    
82
  function render_region($region_id, $panes) {
83
    // Pass through to normal rendering if not in admin mode.
84
    if (!$this->admin) {
85
      return parent::render_region($region_id, $panes);
86
    }
87

    
88
    $content = implode('', $panes);
89

    
90
    $panel_buttons = $this->get_region_links($region_id);
91

    
92
    $output = "<div class='panel-region' id='panel-region-$region_id'>";
93
    $output .= $panel_buttons;
94
    $output .= "<h2 class='label'>" . check_plain($this->plugins['layout']['regions'][$region_id]) . "</h2>";
95
    $output .= $content;
96
    $output .= "</div>";
97

    
98
    return $output;
99
  }
100

    
101
  function render_pane(&$pane) {
102
    // Pass through to normal rendering if not in admin mode.
103
    if (!$this->admin) {
104
      return parent::render_pane($pane);
105
    }
106

    
107
    ctools_include('content');
108
    $content_type = ctools_get_content_type($pane->type);
109

    
110
    // This is just used for the title bar of the pane, not the content itself.
111
    // If we know the content type, use the appropriate title for that type,
112
    // otherwise, set the title using the content itself.
113
    $title = ctools_content_admin_title($content_type, $pane->subtype, $pane->configuration, $this->display->context);
114
    if (!$title) {
115
      $title = t('Deleted/missing content type @type', array('@type' => $pane->type));
116
    }
117

    
118
    $buttons = $this->get_pane_links($pane, $content_type);
119

    
120
    // Render administrative buttons for the pane.
121

    
122
    $block = new stdClass();
123
    if (empty($content_type)) {
124
      $block->title = '<em>' . t('Missing content type') . '</em>';
125
      $block->content = t('This pane\'s content type is either missing or has been deleted. This pane will not render.');
126
    }
127
    else {
128
      $block = ctools_content_admin_info($content_type, $pane->subtype, $pane->configuration, $this->display->context);
129
    }
130

    
131
    $grabber_class = 'grab-title grabber';
132
    // If there are region locks, add them.
133
    if (!empty($pane->locks['type'])) {
134
      if ($pane->locks['type'] == 'regions') {
135
        $settings['Panels']['RegionLock'][$pane->pid] = $pane->locks['regions'];
136
        drupal_add_js($settings, 'setting');
137
      }
138
      else if ($pane->locks['type'] == 'immovable') {
139
        $grabber_class = 'grab-title not-grabber';
140
      }
141
    }
142

    
143
    $output = '';
144
    $class = 'panel-pane';
145

    
146
    if (empty($pane->shown)) {
147
      $class .= ' hidden-pane';
148
    }
149

    
150
    if (isset($this->display->title_pane) && $this->display->title_pane == $pane->pid) {
151
      $class .= ' panel-pane-is-title';
152
    }
153

    
154
    $output = '<div class="' . $class . '" id="panel-pane-' . $pane->pid . '">';
155

    
156
    if (empty($block->title)) {
157
      $block->title = t('No title');
158
    }
159

    
160
    $output .= '<div class="' . $grabber_class . '">';
161
    if ($buttons) {
162
      $output .= '<span class="buttons">' . $buttons . '</span>';
163
    }
164
    $output .= '<span class="text">' . $title . '</span>';
165
    $output .= '</div>'; // grabber
166

    
167
    $output .= '<div class="panel-pane-collapsible">';
168
    $output .= '<div class="pane-title">' . $block->title . '</div>';
169
    $output .= '<div class="pane-content">' . filter_xss_admin(render($block->content)) . '</div>';
170
    $output .= '</div>'; // panel-pane-collapsible
171

    
172
    $output .= '</div>'; // panel-pane
173

    
174
    return $output;
175
  }
176

    
177
  /**
178
   * Get the style links.
179
   *
180
   * This is abstracted out since we have styles on both panes and regions.
181
   */
182
  function get_style_links($type, $id = NULL) {
183
    $info = $this->get_style($type, $id);
184
    $style = $info[0];
185
    $conf = $info[1];
186

    
187
    $style_title = isset($style['title']) ? $style['title'] : t('Default');
188

    
189
    $style_links['title'] = array(
190
      'title' => $style_title,
191
      'attributes' => array('class' => array('panels-text')),
192
    );
193

    
194
    $style_links['change'] = array(
195
      'title' => t('Change'),
196
      'href' => $this->get_url('style-type', $type, $id),
197
      'attributes' => array('class' => array('ctools-use-modal')),
198
    );
199

    
200
    $function = $type != 'pane' ? 'settings form' : 'pane settings form';
201
    if (panels_plugin_get_function('styles', $style, $function)) {
202
      $style_links['settings'] = array(
203
        'title' => t('Settings'),
204
        'href' => $this->get_url('style-settings', $type, $id),
205
        'attributes' => array('class' => array('ctools-use-modal')),
206
      );
207
    }
208

    
209
    return $style_links;
210
  }
211

    
212
  /**
213
   * Get the links for a panel display.
214
   *
215
   * This is abstracted out for easy ajax replacement.
216
   */
217
  function get_display_links() {
218
    $links = array();
219

    
220
    if (user_access('administer panels styles')) {
221
      $style_links = $this->get_style_links('display');
222
      $links[] = array(
223
        'title' => '<span class="dropdown-header">' . t('Style') . '</span>' . theme_links(array('links' => $style_links, 'attributes' => array(), 'heading' => array())),
224
        'html' => TRUE,
225
        'attributes' => array('class' => array('panels-sub-menu')),
226
      );
227
    }
228

    
229
    if (user_access('use panels caching features')) {
230
      $links[] = array(
231
        'title' => '<hr />',
232
        'html' => TRUE,
233
      );
234

    
235
      $method = isset($this->display->cache['method']) ? $this->display->cache['method'] : 0;
236
      $info = panels_get_cache($method);
237
      $cache_method = isset($info['title']) ? $info['title'] : t('No caching');
238

    
239
      $cache_links[] = array(
240
        'title' => $cache_method,
241
        'attributes' => array('class' => array('panels-text')),
242
      );
243
      $cache_links[] = array(
244
        'title' => t('Change'),
245
        'href' => $this->get_url('cache-method', 'display'),
246
        'attributes' => array('class' => array('ctools-use-modal')),
247
      );
248
      if (panels_plugin_get_function('cache', $info, 'settings form')) {
249
        $cache_links[] = array(
250
          'title' => t('Settings'),
251
          'href' => $this->get_url('cache-settings', 'display'),
252
          'attributes' => array('class' => array('ctools-use-modal')),
253
        );
254
      }
255

    
256
      $links[] = array(
257
        'title' => '<span class="dropdown-header">' . t('Caching') . '</span>' . theme_links(array('links' => $cache_links, 'attributes' => array(), 'heading' => array())),
258
        'html' => TRUE,
259
        'attributes' => array('class' => array('panels-sub-menu')),
260
      );
261
    }
262

    
263
    return theme('ctools_dropdown', array('title' => t('Display settings'), 'links' => $links, 'class' => 'panels-display-links'));
264
  }
265

    
266
  /**
267
   * Render the links to display when editing a region.
268
   */
269
  function get_region_links($region_id) {
270
    if (!empty($this->no_edit_links)) {
271
      return '';
272
    }
273
    $links = array();
274
    $links[] = array(
275
      'title' => t('Add content'),
276
      'href' => $this->get_url('select-content', $region_id),
277
      'attributes' => array(
278
        'class' => array('ctools-use-modal'),
279
      ),
280
    );
281

    
282
    if (user_access('administer panels styles')) {
283
      $links[] = array(
284
        'title' => '<hr />',
285
        'html' => TRUE,
286
      );
287

    
288
      $style_links = $this->get_style_links('region', $region_id);
289

    
290
      $links[] = array(
291
        'title' => '<span class="dropdown-header">' . t('Style') . '</span>' . theme_links(array('links' => $style_links, 'attributes' => array(), 'heading' => array())),
292
        'html' => TRUE,
293
        'attributes' => array('class' => array('panels-sub-menu')),
294
      );
295
    }
296

    
297
    return theme('ctools_dropdown', array('title' => theme('image', array('path' => ctools_image_path('icon-addcontent.png', 'panels'))), 'links' => $links, 'image' => TRUE, 'class' => 'pane-add-link panels-region-links-' . $region_id));
298
  }
299

    
300
  /**
301
   * Render the links to display when editing a pane.
302
   */
303
  function get_pane_links($pane, $content_type) {
304
    if (!empty($this->no_edit_links)) {
305
      return '';
306
    }
307
    $links = array();
308

    
309
    if (!empty($pane->shown)) {
310
      $links['top']['disabled'] = array(
311
        'title' => t('Disable this pane'),
312
        'href' => $this->get_url('hide', $pane->pid),
313
        'attributes' => array('class' => array('use-ajax')),
314
      );
315
    }
316
    else {
317
      $links['top']['enable'] = array(
318
        'title' => t('Enable this pane'),
319
        'href' => $this->get_url('show', $pane->pid),
320
        'attributes' => array('class' => array('use-ajax')),
321
      );
322
    }
323

    
324
    if (isset($this->display->title_pane) && $this->display->title_pane == $pane->pid) {
325
      $links['top']['panels-set-title'] = array(
326
        'title' => t('&#x2713;Panel title'),
327
        'html' => TRUE,
328
      );
329
    }
330
    else {
331
      $links['top']['panels-set-title'] = array(
332
        'title' => t('Panel title'),
333
        'href' => $this->get_url('panel-title', $pane->pid),
334
        'attributes' => array('class' => array('use-ajax')),
335
      );
336
    }
337

    
338
    $subtype = ctools_content_get_subtype($content_type, $pane->subtype);
339

    
340
    if (ctools_content_editable($content_type, $subtype, $pane->configuration)) {
341
      $links['top']['settings'] = array(
342
        'title' => isset($content_type['edit text']) ? $content_type['edit text'] : t('Settings'),
343
        'href' => $this->get_url('edit-pane', $pane->pid),
344
        'attributes' => array('class' => array('ctools-use-modal')),
345
      );
346
    }
347

    
348
    if (user_access('administer advanced pane settings')) {
349
      $links['top']['css'] = array(
350
        'title' => t('CSS properties'),
351
        'href' => $this->get_url('pane-css', $pane->pid),
352
        'attributes' => array('class' => array('ctools-use-modal')),
353
      );
354
    }
355

    
356
    if (user_access('administer panels styles')) {
357
      $links['style'] = $this->get_style_links('pane', $pane->pid);
358
    }
359

    
360
    if (user_access('administer pane access')) {
361
      $contexts = $this->display->context;
362
      // Make sure we have the logged in user context
363
      if (!isset($contexts['logged-in-user'])) {
364
        $contexts['logged-in-user'] = ctools_access_get_loggedin_context();
365
      }
366

    
367
      $visibility_links = array();
368

    
369
      if (!empty($pane->access['plugins'])) {
370
        foreach ($pane->access['plugins'] as $id => $test) {
371
          $plugin = ctools_get_access_plugin($test['name']);
372
          $access_title = isset($plugin['title']) ? $plugin['title'] : t('Broken/missing access plugin %plugin', array('%plugin' => $test['name']));
373
          $access_description = ctools_access_summary($plugin, $contexts, $test);
374

    
375
          $visibility_links[] = array(
376
            'title' => $access_description,
377
            'href' => $this->get_url('access-configure-test', $pane->pid, $id),
378
            'attributes' => array('class' => array('ctools-use-modal', 'panels-italic')),
379
          );
380
        }
381
      }
382
      if (empty($visibility_links)) {
383
        $visibility_links['no_rules'] = array(
384
          'title' => t('No rules'),
385
          'attributes' => array('class' => array('panels-text')),
386
        );
387
      }
388

    
389
      $visibility_links['add_rule'] = array(
390
        'title' => t('Add new rule'),
391
        'href' => $this->get_url('access-add-test', $pane->pid),
392
        'attributes' => array('class' => array('ctools-use-modal')),
393
      );
394

    
395
      $visibility_links['settings'] = array(
396
        'title' => t('Settings'),
397
        'href' => $this->get_url('access-settings', $pane->pid),
398
        'attributes' => array('class' => array('ctools-use-modal')),
399
      );
400

    
401
      $links['visibility'] = $visibility_links;
402
    }
403

    
404
    if (user_access('use panels locks')) {
405
      $lock_type = !empty($pane->locks['type']) ? $pane->locks['type'] : 'none';
406
      switch ($lock_type) {
407
        case 'immovable':
408
          $lock_method = t('Immovable');
409
          break;
410
        case 'regions':
411
          $lock_method = t('Regions');
412
          break;
413
        case 'none':
414
        default:
415
          $lock_method = t('No lock');
416
          break;
417
      }
418

    
419
      $lock_links['lock'] = array(
420
        'title' => $lock_method,
421
        'attributes' => array('class' => array('panels-text')),
422
      );
423
      $lock_links['change'] = array(
424
        'title' => t('Change'),
425
        'href' => $this->get_url('lock', $pane->pid),
426
        'attributes' => array('class' => array('ctools-use-modal')),
427
      );
428

    
429
      $links['lock'] = $lock_links;
430
    }
431

    
432
    if (panels_get_caches() && user_access('use panels caching features')) {
433
      $method = isset($pane->cache['method']) ? $pane->cache['method'] : 0;
434
      $info = panels_get_cache($method);
435
      $cache_method = isset($info['title']) ? $info['title'] : t('No caching');
436
      $cache_links['title'] = array(
437
        'title' => $cache_method,
438
        'attributes' => array('class' => array('panels-text')),
439
      );
440
      $cache_links['change'] = array(
441
        'title' => t('Change'),
442
        'href' => $this->get_url('cache-method', $pane->pid),
443
        'attributes' => array('class' => array('ctools-use-modal')),
444
      );
445
      if (panels_plugin_get_function('cache', $info, 'settings form')) {
446
        $cache_links['settings'] = array(
447
          'title' => t('Settings'),
448
          'href' => $this->get_url('cache-settings', $pane->pid),
449
          'attributes' => array('class' => array('ctools-use-modal')),
450
        );
451
      }
452

    
453
      $links['cache'] = $cache_links;
454
    }
455

    
456
    $links['bottom']['remove'] = array(
457
      'title' => t('Remove'),
458
      'href' => '#',
459
      'attributes' => array(
460
        'class' => array('pane-delete'),
461
        'id' => "pane-delete-panel-pane-$pane->pid",
462
      ),
463
    );
464

    
465
    // Allow others to add/remove links from pane context menu.
466
    // Grouped by 'top', 'style', 'visibility', 'lock', 'cache' and 'bottom'
467
    drupal_alter('get_pane_links', $links, $pane, $content_type);
468

    
469
    $dropdown_links = $links['top'];
470
    foreach (array(
471
  'style' => 'Style',
472
  'visibility' => 'Visibility rules',
473
  'lock' => 'Locking',
474
  'cache' => 'Caching'
475
    ) as $category => $label) {
476
      $dropdown_links[] = array(
477
        'title' => '<hr />',
478
        'html' => TRUE,
479
      );
480
      $dropdown_links[] = array(
481
        'title' => '<span class="dropdown-header">' . t($label) . '</span>' . theme_links(array('links' => $links[$category], 'attributes' => array(), 'heading' => array())),
482
        'html' => TRUE,
483
        'attributes' => array('class' => array('panels-sub-menu')),
484
      );
485
    }
486

    
487
    $dropdown_links[] = array(
488
      'title' => '<hr />',
489
      'html' => TRUE,
490
    );
491
    $dropdown_links = array_merge($dropdown_links, $links['bottom']);
492

    
493
    return theme('ctools_dropdown', array('title' => theme('image', array('path' => ctools_image_path('icon-configure.png', 'panels'))), 'links' => $dropdown_links, 'image' => TRUE));
494
  }
495

    
496
  // -----------------------------------------------------------------------
497
  // Display edit AJAX callbacks and helpers.
498

    
499
  /**
500
   * Generate a URL path for the AJAX editor.
501
   */
502
  function get_url() {
503
    $args = func_get_args();
504
    $command = array_shift($args);
505
    $url = 'panels/ajax/' . $this->plugin['name'] . '/' . $command . '/' . $this->display->cache_key;
506
    if ($args) {
507
      $url .= '/' . implode('/', $args);
508
    }
509

    
510
    return $url;
511
  }
512

    
513
  /**
514
   * AJAX command to show a pane.
515
   */
516
  function ajax_show($pid = NULL) {
517
    if (empty($this->display->content[$pid])) {
518
      ctools_ajax_render_error(t('Invalid pane id.'));
519
    }
520

    
521
    $this->display->content[$pid]->shown = TRUE;
522
    panels_edit_cache_set($this->cache);
523

    
524
    $this->command_update_pane($pid);
525
  }
526

    
527
  /**
528
   * AJAX command to show a pane.
529
   */
530
  function ajax_hide($pid = NULL) {
531
    if (empty($this->display->content[$pid])) {
532
      ctools_ajax_render_error(t('Invalid pane id.'));
533
    }
534

    
535
    $this->display->content[$pid]->shown = FALSE;
536
    panels_edit_cache_set($this->cache);
537

    
538
    $this->command_update_pane($pid);
539
  }
540

    
541
  /**
542
   * AJAX command to present a dialog with a list of available content.
543
   */
544
  function ajax_select_content($region = NULL, $category = NULL) {
545
    if (!array_key_exists($region, $this->plugins['layout']['regions'])) {
546
      ctools_modal_render(t('Error'), t('Invalid input'));
547
    }
548

    
549
    $title = t('Add content to !s', array('!s' => $this->plugins['layout']['regions'][$region]));
550

    
551
    $categories = $this->get_categories($this->cache->content_types);
552

    
553
    if (empty($categories)) {
554
      $output = t('There are no content types you may add to this display.');
555
    }
556
    else {
557
      $output = theme('panels_add_content_modal', array('renderer' => $this, 'categories' => $categories, 'category' => $category, 'region' => $region));
558
    }
559
    $this->commands[] = ctools_modal_command_display($title, $output);
560
  }
561

    
562
  /**
563
   * Return the category name and the category key of a given content
564
   * type.
565
   *
566
   * @todo -- this should be in CTools.
567
   */
568
  function get_category($content_type) {
569
    if (!empty($content_type['top level'])) {
570
      $category = 'root';
571
    }
572
    else if (isset($content_type['category'])) {
573
      if (is_array($content_type['category'])) {
574
        list($category, $weight) = $content_type['category'];
575
      }
576
      else {
577
        $category = $content_type['category'];
578
      }
579
    }
580
    else {
581
      $category = t('Uncategorized');
582
    }
583

    
584
    return array(preg_replace('/[^a-z0-9]/', '-', strtolower($category)), $category);
585
  }
586

    
587

    
588
  /**
589
   * Create a list of categories from all of the content type.
590
   *
591
   * @return array
592
   *   An array of categories. Each entry in the array will also be an array
593
   *   with 'title' as the printable title of the category, and 'content'
594
   *   being an array of all content in the category. Each item in the 'content'
595
   *   array contain the array plugin definition so that it can be later
596
   *   found in the content array. They will be keyed by the title so that they
597
   *   can be sorted.
598
   */
599
  function get_categories($content_types) {
600
    $categories = array();
601
    $category_names = array();
602

    
603
    foreach ($content_types as $type_name => $subtypes) {
604
      foreach ($subtypes as $subtype_name => $content_type) {
605
        list($category_key, $category) = $this->get_category($content_type);
606

    
607
        if (empty($categories[$category_key])) {
608
          $categories[$category_key] = array(
609
            'title' => $category,
610
            'content' => array(),
611
          );
612
          $category_names[$category_key] = $category;
613
        }
614

    
615
        $content_title = filter_xss_admin($content_type['title']);
616

    
617
        // Ensure content with the same title doesn't overwrite each other.
618
        while (isset($categories[$category_key]['content'][$content_title])) {
619
          $content_title .= '-';
620
        }
621

    
622
        $categories[$category_key]['content'][$content_title] = $content_type;
623
        $categories[$category_key]['content'][$content_title]['type_name'] = $type_name;
624
        $categories[$category_key]['content'][$content_title]['subtype_name'] = $subtype_name;
625
      }
626
    }
627

    
628
    // Now sort
629
    natcasesort($category_names);
630
    foreach ($category_names as $category => $name) {
631
      $output[$category] = $categories[$category];
632
    }
633

    
634
    return $output;
635
  }
636

    
637
  /**
638
   * AJAX entry point to add a new pane.
639
   */
640
  function ajax_add_pane($region = NULL, $type_name = NULL, $subtype_name = NULL, $step = NULL) {
641
    $content_type = ctools_get_content_type($type_name);
642
    $subtype = ctools_content_get_subtype($content_type, $subtype_name);
643

    
644
    // Determine if we are adding a different pane than previously cached. This
645
    // is used to load the different pane into cache so that multistep forms
646
    // have the correct context instead of a previously cached version that
647
    // does not match the pane currently being added.
648
    $is_different_pane = FALSE;
649
    if (isset($this->cache) && isset($this->cache->new_pane)) {
650
      $diff_type = $type_name != $this->cache->new_pane->type;
651
      $diff_subtype = $subtype_name != $this->cache->new_pane->subtype;
652

    
653
      $is_different_pane = $diff_type || $diff_subtype;
654
    }
655

    
656
    if (!isset($step) || !isset($this->cache->new_pane) || $is_different_pane) {
657
      $pane = panels_new_pane($type_name, $subtype_name, TRUE);
658
      $this->cache->new_pane = &$pane;
659
    }
660
    else {
661
      $pane = &$this->cache->new_pane;
662
    }
663

    
664
    $form_state = array(
665
      'display' => &$this->cache->display,
666
      'contexts' => $this->cache->display->context,
667
      'pane' => &$pane,
668
      'cache_key' => $this->display->cache_key,
669
      'display cache' => &$this->cache,
670
      'ajax' => TRUE,
671
      'modal' => TRUE,
672
      // This will force the system to not automatically render.
673
      'modal return' => TRUE,
674
      'commands' => array(),
675
    );
676

    
677
    $form_info = array(
678
      'path' => $this->get_url('add-pane', $region, $type_name, $subtype_name, '%step'),
679
      'show cancel' => TRUE,
680
      'next callback' => 'panels_ajax_edit_pane_next',
681
      'finish callback' => 'panels_ajax_edit_pane_finish',
682
      'cancel callback' => 'panels_ajax_edit_pane_cancel',
683
    );
684

    
685
    $output = ctools_content_form('add', $form_info, $form_state, $content_type, $pane->subtype, $subtype, $pane->configuration, $step);
686

    
687
    // If $rc is FALSE, there was no actual form.
688
    if ($output === FALSE || !empty($form_state['complete'])) {
689
      // References get blown away with AJAX caching. This will fix that.
690
      $pane = $form_state['pane'];
691
      unset($this->cache->new_pane);
692

    
693
      // Add the pane to the display
694
      $this->display->add_pane($pane, $region);
695
      panels_edit_cache_set($this->cache);
696

    
697
      // Tell the client to draw the pane
698
      $this->command_add_pane($pane);
699

    
700
      // Dismiss the modal.
701
      $this->commands[] = ctools_modal_command_dismiss();
702
    }
703
    else if (!empty($form_state['cancel'])) {
704
      // If cancelling, return to the activity.
705
      list($category_key, $category) = $this->get_category($subtype);
706
      $this->ajax_select_content($region, $category_key);
707
    }
708
    else {
709
      // This overwrites any previous commands.
710
      $this->commands = ctools_modal_form_render($form_state, $output);
711
    }
712
  }
713

    
714
  /**
715
   * AJAX entry point to edit a pane.
716
   */
717
  function ajax_edit_pane($pid = NULL, $step = NULL) {
718
    if (empty($this->cache->display->content[$pid])) {
719
      ctools_modal_render(t('Error'), t('Invalid pane id.'));
720
    }
721

    
722
    $pane = &$this->cache->display->content[$pid];
723

    
724
    $content_type = ctools_get_content_type($pane->type);
725
    $subtype = ctools_content_get_subtype($content_type, $pane->subtype);
726

    
727
    $form_state = array(
728
      'display' => &$this->cache->display,
729
      'contexts' => $this->cache->display->context,
730
      'pane' => &$pane,
731
      'display cache' => &$this->cache,
732
      'ajax' => TRUE,
733
      'modal' => TRUE,
734
      'modal return' => TRUE,
735
      'commands' => array(),
736
    );
737

    
738
    $form_info = array(
739
      'path' => $this->get_url('edit-pane', $pid, '%step'),
740
      'show cancel' => TRUE,
741
      'next callback' => 'panels_ajax_edit_pane_next',
742
      'finish callback' => 'panels_ajax_edit_pane_finish',
743
      'cancel callback' => 'panels_ajax_edit_pane_cancel',
744
    );
745

    
746
    $output = ctools_content_form('edit', $form_info, $form_state, $content_type, $pane->subtype,  $subtype, $pane->configuration, $step);
747

    
748
    // If $rc is FALSE, there was no actual form.
749
    if ($output === FALSE || !empty($form_state['cancel'])) {
750
      // Dismiss the modal.
751
      $this->commands[] = ctools_modal_command_dismiss();
752
    }
753
    else if (!empty($form_state['complete'])) {
754
      // References get blown away with AJAX caching. This will fix that.
755
      $this->cache->display->content[$pid] = $form_state['pane'];
756

    
757
      // Conditionally overwrite the context for this panel if present in the form state.
758
      if (!empty($form_state['display_cache']->display->context)) {
759
        $this->cache->display->context = $form_state['display_cache']->display->context;
760
      }
761

    
762
      panels_edit_cache_set($this->cache);
763
      $this->command_update_pane($pid);
764
      $this->commands[] = ctools_modal_command_dismiss();
765
    }
766
    else {
767
      // This overwrites any previous commands.
768
      $this->commands = ctools_modal_form_render($form_state, $output);
769
    }
770
  }
771

    
772
  /**
773
   * AJAX entry point to select which pane is currently the title.
774
   *
775
   * @param string $pid
776
   *   The pane id for the pane object whose title state we're setting.
777
   */
778
  function ajax_panel_title($pid = NULL) {
779
    if (empty($this->display->content[$pid])) {
780
      ctools_ajax_render_error(t('Invalid pane id.'));
781
    }
782

    
783
    $pane = &$this->display->content[$pid];
784

    
785
    $old_title = !empty($this->display->title_pane) ? $this->display->title_pane : NULL;
786
    $this->display->title_pane = $pid;
787

    
788
    panels_edit_cache_set($this->cache);
789

    
790
    $this->command_update_pane($pane);
791

    
792
    if ($old_title && !empty($this->cache->display->content[$old_title])) {
793
      $this->command_update_pane($this->cache->display->content[$old_title]);
794
    }
795
  }
796

    
797
  /**
798
   * AJAX entry point to configure the cache method for a pane or the display.
799
   *
800
   * @param string $pid
801
   *   Either a pane id for a pane in the display, or 'display' to edit the
802
   *   display cache settings.
803
   */
804
  function ajax_cache_method($pid = NULL) {
805
    ctools_include('content');
806
    // This lets us choose whether we're doing the display's cache or
807
    // a pane's.
808
    if ($pid == 'display') {
809
      $conf = &$this->display->cache;
810
      $title = t('Cache method for this display');
811
    }
812
    else if (!empty($this->display->content[$pid])) {
813
      $pane = &$this->display->content[$pid];
814
      $subtype = ctools_content_get_subtype($pane->type, $pane->subtype);
815
      $conf = &$pane->cache;
816
      $title = t('Cache method for !subtype_title', array('!subtype_title' => $subtype['title']));
817
    }
818
    else {
819
      ctools_modal_render(t('Error'), t('Invalid pane id.'));
820
    }
821

    
822
    $form_state = array(
823
      'display' => &$this->display,
824
      'conf' => &$conf,
825
      'title' => $title,
826
      'ajax' => TRUE,
827
    );
828

    
829
    $output = ctools_modal_form_wrapper('panels_edit_cache_method_form', $form_state);
830
    if (empty($form_state['executed'])) {
831
      $this->commands = $output;
832
      return;
833
    }
834

    
835
    // Preserve this; this way we don't actually change the method until they
836
    // have saved the form.
837
    $info = panels_get_cache($form_state['method']);
838
    $function = panels_plugin_get_function('cache', $info, 'settings form');
839
    if (!$function) {
840
      $conf['method'] = $form_state['method'];
841
      $conf['settings'] = array();
842
      panels_edit_cache_set($this->cache);
843

    
844
      $this->commands[] = ctools_modal_command_dismiss();
845

    
846
      if ($pid != 'display') {
847
        $this->command_update_pane($pane);
848
      }
849
      else {
850
        $this->command_update_display_links();
851
      }
852
    }
853
    else {
854
      $this->cache->method = $form_state['method'];
855
      panels_edit_cache_set($this->cache);
856
      // send them to next form.
857
      return $this->ajax_cache_settings($pid);
858
    }
859
  }
860

    
861
  /**
862
   * AJAX entry point to configure the cache settings for a pane or the display.
863
   *
864
   * @param string $pid
865
   *   Either a pane id for a pane in the display, or 'display' to edit the
866
   *   display cache settings.
867
   */
868
  function ajax_cache_settings($pid = 0) {
869
    ctools_include('content');
870

    
871
    // This lets us choose whether we're doing the display's cache or
872
    // a pane's.
873
    if ($pid == 'display') {
874
      $conf = &$this->display->cache;
875
      $title = t('Cache settings for this display');
876
    }
877
    else if (!empty($this->display->content[$pid])) {
878
      $pane = &$this->display->content[$pid];
879
      $subtype = ctools_content_get_subtype($pane->type, $pane->subtype);
880

    
881
      $conf = &$pane->cache;
882
      $title = t('Cache settings for !subtype_title', array('!subtype_title' => $subtype['title']));
883
    }
884
    else {
885
      ctools_modal_render(t('Error'), t('Invalid pane id.'));
886
    }
887

    
888
    if (isset($this->cache->method) && (empty($conf['method']) || $conf['method'] != $this->cache->method)) {
889
      $conf['method'] = $this->cache->method;
890
      $info = panels_get_cache($conf['method']);
891
      $conf['settings'] = isset($info['defaults']) ? $info['defaults'] : array();
892
    }
893

    
894
    $form_state = array(
895
      'display' => &$this->display,
896
      'pid' => $pid,
897
      'conf' => &$conf,
898
      'ajax' => TRUE,
899
      'title' => $title,
900
      'url' => url($this->get_url('cache-settings', $pid), array('absolute' => TRUE)),
901
    );
902

    
903
    $output = ctools_modal_form_wrapper('panels_edit_cache_settings_form', $form_state);
904
    if (empty($form_state['executed'])) {
905
      $this->commands = $output;
906
      return;
907
    }
908

    
909
    panels_edit_cache_set($this->cache);
910

    
911
    $this->commands[] = ctools_modal_command_dismiss();
912

    
913
    if ($pid != 'display') {
914
      $this->command_update_pane($pane);
915
    }
916
    else {
917
      $this->command_update_display_links();
918
    }
919
  }
920

    
921
  /**
922
   * AJAX entry point to select the style for a display, region or pane.
923
   *
924
   * @param string $type
925
   *   Either display, region or pane
926
   * @param $pid
927
   *   The pane id, if a pane. The region id, if a region.
928
   */
929
  function ajax_style_type($type, $pid = NULL) {
930
    // This lets us choose whether we're doing the display's cache or
931
    // a pane's.
932
    switch ($type) {
933
      case 'display':
934
        $style = isset($this->display->panel_settings['style']) ? $this->display->panel_settings['style'] : 'default';
935
        $title = t('Default style for this display');
936
        break;
937

    
938
      case 'region':
939
        $style = isset($this->display->panel_settings[$pid]['style']) ? $this->display->panel_settings[$pid]['style'] : '-1'; // -1 signifies to use the default setting.
940
        $title = t('Panel style for region "!region"', array('!region' => $this->plugins['layout']['regions'][$pid]));
941
        break;
942

    
943
      case 'pane':
944
        ctools_include('content');
945
        $pane = &$this->display->content[$pid];
946
        $style = isset($pane->style['style']) ? $pane->style['style'] : 'default';
947
        $subtype = ctools_content_get_subtype($pane->type, $pane->subtype);
948
        $title = t('Pane style for "!pane"', array('!pane' => $subtype['title']));
949
        break;
950

    
951
      default:
952
        ctools_modal_render(t('Error'), t('Invalid pane id.'));
953
    }
954
    $info = $this->get_style($type, $pid);
955
    $style_plugin = $info[0];
956
    $style_settings = $info[1];
957

    
958
    // Backward compatibility: Translate old-style stylizer to new style
959
    // stylizer.
960
    if ($style == 'stylizer' && !empty($style_settings['style']) && $style_settings['style'] != '$') {
961
      $style = 'stylizer:' . $style_settings['style'];
962
    }
963

    
964
    $form_state = array(
965
      'display' => &$this->display,
966
      'style' => $style,
967
      'pane' => ($type == 'pane') ? $this->display->content[$pid] : NULL,
968
      'title' => $title,
969
      'ajax' => TRUE,
970
      'type' => $type,
971
    );
972

    
973
    $output = ctools_modal_form_wrapper('panels_edit_style_type_form', $form_state);
974
    if (empty($form_state['executed'])) {
975
      $this->commands = $output;
976
      return;
977
    }
978

    
979
    // Preserve this; this way we don't actually change the method until they
980
    // have saved the form.
981
    $style = panels_get_style($form_state['style']);
982
    $function = panels_plugin_get_function('styles', $style, ($type == 'pane') ? 'pane settings form' : 'settings form');
983
    if (!$function) {
984
      if (isset($this->cache->style)) {
985
        unset($this->cache->style);
986
      }
987

    
988
      // If there's no settings form, just change the style and exit.
989
      switch($type) {
990
        case 'display':
991
          $this->display->panel_settings['style'] = $form_state['style'];
992
          if (isset($this->display->panel_settings['style_settings']['default'])) {
993
            unset($this->display->panel_settings['style_settings']['default']);
994
          }
995
          break;
996

    
997
        case 'region':
998
          $this->display->panel_settings[$pid]['style'] = $form_state['style'];
999
          if (isset($this->display->panel_settings['style_settings'][$pid])) {
1000
            unset($this->display->panel_settings['style_settings'][$pid]);
1001
          }
1002
          break;
1003

    
1004
        case 'pane':
1005
          $pane->style['style'] = $form_state['style'];
1006
          if (isset($pane->style['settings'])) {
1007
            unset($pane->style['settings']);
1008
          }
1009

    
1010
          break;
1011
      }
1012
      panels_edit_cache_set($this->cache);
1013

    
1014
      $this->commands[] = ctools_modal_command_dismiss();
1015

    
1016
      if ($type == 'pane') {
1017
        $this->command_update_pane($pane);
1018
      }
1019
      else if ($type == 'region') {
1020
        $this->command_update_region_links($pid);
1021
      }
1022
      else {
1023
        $this->command_update_display_links();
1024
      }
1025
    }
1026
    else {
1027
      if ($form_state['style'] != $form_state['old_style']) {
1028
        $this->cache->style = $form_state['style'];
1029
        panels_edit_cache_set($this->cache);
1030
      }
1031

    
1032
      // send them to next form.
1033
      return $this->ajax_style_settings($type, $pid);
1034
    }
1035
  }
1036

    
1037
  /**
1038
   * Get the appropriate style from the panel in the cache.
1039
   *
1040
   * Since we have styles for regions, panes and the display itself, and
1041
   * they are stored differently, we use this method to simplify getting
1042
   * style information into a way that's easy to cope with.
1043
   */
1044
  function get_style($type, $pid = '') {
1045
    if (isset($this->cache->style)) {
1046
      $style = panels_get_style($this->cache->style);
1047
      $defaults = isset($style['defaults']) ? $style['defaults'] : array();
1048
      // Get the &$conf variable based upon whose style we're editing.
1049
      switch ($type) {
1050
        case 'display':
1051
          $this->display->panel_settings['style'] = $this->cache->style;
1052
          $this->display->panel_settings['style_settings']['default'] = $defaults;
1053
          break;
1054

    
1055
        case 'region':
1056
          $this->display->panel_settings[$pid]['style'] = $this->cache->style;
1057
          $this->display->panel_settings['style_settings'][$pid] = $defaults;
1058
          break;
1059

    
1060
        case 'pane':
1061
          $pane = &$this->display->content[$pid];
1062
          $pane->style['style'] = $this->cache->style;
1063
          $pane->style['settings'] = $defaults;
1064
          $conf = &$pane->style['settings'];
1065
          break;
1066
      }
1067
    }
1068
    else {
1069
      switch ($type) {
1070
        case 'display':
1071
          $style = panels_get_style((!empty($this->display->panel_settings['style'])) ? $this->display->panel_settings['style'] : 'default');
1072
          break;
1073

    
1074
        case 'region':
1075
          $style = panels_get_style((!empty($this->display->panel_settings[$pid]['style'])) ? $this->display->panel_settings[$pid]['style'] : '-1');
1076
          break;
1077

    
1078
        case 'pane':
1079
          $pane = &$this->display->content[$pid];
1080
          $style = panels_get_style(!empty($pane->style['style']) ? $pane->style['style'] : 'default');
1081
          break;
1082
      }
1083
    }
1084

    
1085
    // Set up our $conf reference.
1086
    switch ($type) {
1087
      case 'display':
1088
        $conf = &$this->display->panel_settings['style_settings']['default'];
1089
        break;
1090

    
1091
      case 'region':
1092
        $conf = &$this->display->panel_settings['style_settings'][$pid];
1093
        break;
1094

    
1095
      case 'pane':
1096
        ctools_include('content');
1097
        $pane = &$this->display->content[$pid];
1098
        $conf = &$pane->style['settings'];
1099
        break;
1100
    }
1101

    
1102
    // Backward compatibility: Translate old-style stylizer to new style
1103
    // stylizer.
1104
    if ($style['name'] == 'stylizer' && !empty($conf['style']) && $conf['style'] != '$') {
1105
      $style = panels_get_style('stylizer:' . $conf['style']);
1106
    }
1107

    
1108
    return array($style, &$conf);
1109
  }
1110

    
1111
  /**
1112
   * AJAX entry point to configure the style for a display, region or pane.
1113
   *
1114
   * @param string $type
1115
   *   Either display, region or pane
1116
   * @param $pid
1117
   *   The pane id, if a pane. The region id, if a region.
1118
   */
1119
  function ajax_style_settings($type, $pid = '') {
1120
    $info = $this->get_style($type, $pid);
1121
    $style = $info[0];
1122
    $conf = &$info[1];
1123

    
1124
    switch ($type) {
1125
      case 'display':
1126
        $title = t('Style settings for @style (display)', array('@style' => $style['title']));
1127
        break;
1128

    
1129
      case 'region':
1130
        $title = t('Style settings for style @style (Region "!region")', array('@style' => $style['title'], '!region' => $this->plugins['layout']['regions'][$pid]));
1131
        break;
1132

    
1133
      case 'pane':
1134
        ctools_include('content');
1135
        $pane = &$this->display->content[$pid];
1136
        $subtype = ctools_content_get_subtype($pane->type, $pane->subtype);
1137
        $title = t('Style settings for style @style (Pane "!pane")', array('@style' => $style['title'], '!pane' => $subtype['title']));
1138
        break;
1139
    }
1140

    
1141
    $form_state = array(
1142
      'display' => &$this->display,
1143
      'type' => $type,
1144
      'pid' => $pid,
1145
      'conf' => &$conf,
1146
      'style' => $style,
1147
      'ajax' => TRUE,
1148
      'title' => $title,
1149
      'url' => url($this->get_url('style-settings', $type, $pid), array('absolute' => TRUE)),
1150
      'renderer' => &$this,
1151
    );
1152

    
1153
    $output = ctools_modal_form_wrapper('panels_edit_style_settings_form', $form_state);
1154
    if (empty($form_state['executed'])) {
1155
      $this->commands = $output;
1156
      return;
1157
    }
1158

    
1159
    if (isset($this->cache->style)) {
1160
      unset($this->cache->style);
1161
    }
1162

    
1163
    // Copy settings from form state back into the cache.
1164
    if(!empty($form_state['values']['settings'])) {
1165
      $this->cache->display->content[$pid]->style['settings'] = $form_state['values']['settings'];
1166
    }
1167

    
1168
    panels_edit_cache_set($this->cache);
1169

    
1170
    $this->commands[] = ctools_modal_command_dismiss();
1171

    
1172
    if ($type == 'pane') {
1173
      $this->command_update_pane($pane);
1174
    }
1175
    else if ($type == 'region') {
1176
      $this->command_update_region_links($pid);
1177
    }
1178
    else {
1179
      $this->command_update_display_links();
1180
    }
1181
  }
1182

    
1183
  /**
1184
   * AJAX entry point to configure CSS for a pane.
1185
   *
1186
   * @param $pid
1187
   *   The pane id to edit.
1188
   */
1189
  function ajax_pane_css($pid = NULL) {
1190
    if (empty($this->display->content[$pid])) {
1191
      ctools_modal_render(t('Error'), t('Invalid pane id.'));
1192
    }
1193

    
1194
    $pane = &$this->display->content[$pid];
1195
    $subtype = ctools_content_get_subtype($pane->type, $pane->subtype);
1196

    
1197
    $form_state = array(
1198
      'display' => &$this->display,
1199
      'pane' => &$pane,
1200
      'ajax' => TRUE,
1201
      'title' => t('Configure CSS on !subtype_title', array('!subtype_title' => $subtype['title'])),
1202
    );
1203

    
1204
    $output = ctools_modal_form_wrapper('panels_edit_configure_pane_css_form', $form_state);
1205
    if (empty($form_state['executed'])) {
1206
      $this->commands = $output;
1207
      return;
1208
    }
1209

    
1210
    panels_edit_cache_set($this->cache);
1211
    $this->command_update_pane($pid);
1212
    $this->commands[] = ctools_modal_command_dismiss();
1213
  }
1214

    
1215
  /**
1216
   * AJAX entry point to configure CSS for a pane.
1217
   *
1218
   * @param $pid
1219
   *   The pane id to edit.
1220
   */
1221
  function ajax_lock($pid = NULL) {
1222
    if (empty($this->display->content[$pid])) {
1223
      ctools_modal_render(t('Error'), t('Invalid pane id.'));
1224
    }
1225

    
1226
    $pane = &$this->display->content[$pid];
1227
    $subtype = ctools_content_get_subtype($pane->type, $pane->subtype);
1228

    
1229
    $form_state = array(
1230
      'display' => &$this->display,
1231
      'pane' => &$pane,
1232
      'ajax' => TRUE,
1233
      'title' => t('Configure lock on !subtype_title', array('!subtype_title' => $subtype['title'])),
1234
    );
1235

    
1236
    $output = ctools_modal_form_wrapper('panels_edit_configure_pane_lock_form', $form_state);
1237
    if (empty($form_state['executed'])) {
1238
      $this->commands = $output;
1239
      return;
1240
    }
1241

    
1242
    panels_edit_cache_set($this->cache);
1243
    $this->command_update_pane($pid);
1244
    $this->commands[] = ctools_modal_command_dismiss();
1245
  }
1246

    
1247
  /**
1248
   * AJAX entry point to configure access settings for a pane.
1249
   *
1250
   * @param $pid
1251
   *   The pane id to edit.
1252
   */
1253
  function ajax_access_settings($pid = NULL) {
1254
    if (empty($this->display->content[$pid])) {
1255
      ctools_modal_render(t('Error'), t('Invalid pane id.'));
1256
    }
1257

    
1258
    $pane = &$this->display->content[$pid];
1259
    $subtype = ctools_content_get_subtype($pane->type, $pane->subtype);
1260

    
1261
    $form_state = array(
1262
      'display' => &$this->display,
1263
      'pane' => &$pane,
1264
      'ajax' => TRUE,
1265
      'title' => t('Access settings on !subtype_title', array('!subtype_title' => $subtype['title'])),
1266
    );
1267

    
1268
    $output = ctools_modal_form_wrapper('panels_edit_configure_access_settings_form', $form_state);
1269
    if (empty($form_state['executed'])) {
1270
      $this->commands = $output;
1271
      return;
1272
    }
1273

    
1274
    panels_edit_cache_set($this->cache);
1275
    $this->command_update_pane($pid);
1276
    $this->commands[] = ctools_modal_command_dismiss();
1277
  }
1278

    
1279
  /**
1280
   * AJAX entry point for to add a visibility rule.
1281
   */
1282
  function ajax_access_add_test($pid = NULL) {
1283
    if (empty($this->display->content[$pid])) {
1284
      ctools_modal_render(t('Error'), t('Invalid pane id.'));
1285
    }
1286

    
1287
    $pane = &$this->display->content[$pid];
1288
    $subtype = ctools_content_get_subtype($pane->type, $pane->subtype);
1289

    
1290
    $form_state = array(
1291
      'display' => &$this->display,
1292
      'pane' => &$pane,
1293
      'ajax' => TRUE,
1294
      'title' => t('Add visibility rule for !subtype_title', array('!subtype_title' => $subtype['title'])),
1295
    );
1296

    
1297
    $output = ctools_modal_form_wrapper('panels_edit_add_access_test_form', $form_state);
1298
    if (!empty($form_state['executed'])) {
1299
      // Set up the plugin in cache
1300
      $plugin = ctools_get_access_plugin($form_state['values']['type']);
1301
      $this->cache->new_plugin = ctools_access_new_test($plugin);
1302
      panels_edit_cache_set($this->cache);
1303

    
1304
      // go to the next step.
1305
      return $this->ajax_access_configure_test($pid, 'add');
1306
    }
1307

    
1308
    $this->commands = $output;
1309
  }
1310

    
1311
  /**
1312
   * AJAX entry point for to configure vsibility rule.
1313
   */
1314
  function ajax_access_configure_test($pid = NULL, $id = NULL) {
1315
    if (empty($this->display->content[$pid])) {
1316
      ctools_modal_render(t('Error'), t('Invalid pane id.'));
1317
    }
1318

    
1319
    $pane = &$this->display->content[$pid];
1320
    $subtype = ctools_content_get_subtype($pane->type, $pane->subtype);
1321

    
1322
    // Set this up here because $id gets changed later.
1323
    $url = $this->get_url('access-configure-test', $pid, $id);
1324

    
1325
    // If we're adding a new one, get the stored data from cache and
1326
    // add it. It's stored as a cache so that if this is closed
1327
    // we don't accidentally add an unconfigured plugin.
1328
    if ($id == 'add') {
1329
      $pane->access['plugins'][] = $this->cache->new_plugin;
1330
      $id = max(array_keys($pane->access['plugins']));
1331
    }
1332
    else if (empty($pane->access['plugins'][$id])) {
1333
      ctools_modal_render(t('Error'), t('Invalid test id.'));
1334
    }
1335

    
1336
    $form_state = array(
1337
      'display' => &$this->display,
1338
      'pane' => &$pane,
1339
      'ajax' => TRUE,
1340
      'title' => t('Configure visibility rule for !subtype_title', array('!subtype_title' => $subtype['title'])),
1341
      'test' => &$pane->access['plugins'][$id],
1342
      'plugin' => ctools_get_access_plugin($pane->access['plugins'][$id]['name']),
1343
      'url' => url($url, array('absolute' => TRUE)),
1344
    );
1345

    
1346
    $output = ctools_modal_form_wrapper('panels_edit_configure_access_test_form', $form_state);
1347
    if (empty($form_state['executed'])) {
1348
      $this->commands = $output;
1349
      return;
1350
    }
1351

    
1352
    // Unset the new plugin
1353
    if (isset($this->cache->new_plugin)) {
1354
      unset($this->cache->new_plugin);
1355
    }
1356

    
1357
    if (!empty($form_state['remove'])) {
1358
      unset($pane->access['plugins'][$id]);
1359
    }
1360

    
1361
    panels_edit_cache_set($this->cache);
1362
    $this->command_update_pane($pid);
1363
    $this->commands[] = ctools_modal_command_dismiss();
1364
  }
1365

    
1366
  /**
1367
   * AJAX Router function for layout owned AJAX calls.
1368
   *
1369
   * Layouts like the flexible layout builder need callbacks of their own.
1370
   * This allows those layouts to simply declare their callbacks and use
1371
   * them with $this->get_url('layout', $command).
1372
   */
1373
  function ajax_layout() {
1374
    $args = func_get_args();
1375
    if (empty($args)) {
1376
      return MENU_NOT_FOUND;
1377
    }
1378

    
1379
    $command = array_shift($args);
1380
    if (empty($this->plugins['layout']['ajax'][$command]) || !function_exists($this->plugins['layout']['ajax'][$command])) {
1381
      return MENU_NOT_FOUND;
1382
    }
1383

    
1384
    // Make sure the this is always available to the called functions.
1385
    array_unshift($args, $this);
1386
    return call_user_func_array($this->plugins['layout']['ajax'][$command], $args);
1387
  }
1388

    
1389
  /**
1390
   * AJAX Router function for style owned AJAX calls.
1391
   *
1392
   * Styles like the stylizer need AJAX callbacks of their own. This
1393
   * allows the system to figure out which style is being referenced,
1394
   * load it, and execute the callback.
1395
   *
1396
   * This allows those layouts to simply declare their callbacks and use
1397
   * them using $this->get_url('style', $command, $type, $pid).
1398
   */
1399
  function ajax_style() {
1400
    $args = func_get_args();
1401
    if (count($args) < 3) {
1402
      return MENU_NOT_FOUND;
1403
    }
1404

    
1405
    $command = array_shift($args);
1406
    $type = array_shift($args);
1407
    $pid = array_shift($args);
1408

    
1409
    $info = $this->get_style($type, $pid);
1410

    
1411
    $style = $info[0];
1412
    $conf = &$info[1];
1413

    
1414
    if (empty($style['ajax'][$command]) || !function_exists($style['ajax'][$command])) {
1415
      return MENU_NOT_FOUND;
1416
    }
1417

    
1418
    // Make sure the this is always available to the called functions.
1419
    $args = array_merge(array(&$this, $style, &$conf, $type, $pid), $args);
1420
    return call_user_func_array($style['ajax'][$command], $args);
1421
  }
1422

    
1423
  // ------------------------------------------------------------------------
1424
  // AJAX command generators
1425
  //
1426
  // These are used to make sure that child implementations can control their
1427
  // own AJAX commands as needed.
1428

    
1429
  /**
1430
   * Create a command array to redraw a pane.
1431
   */
1432
  function command_update_pane($pid) {
1433
    if (is_object($pid)) {
1434
      $pane = $pid;
1435
    }
1436
    else {
1437
      $pane = $this->display->content[$pid];
1438
    }
1439

    
1440
    $this->commands[] = ajax_command_replace("#panel-pane-$pane->pid", $this->render_pane($pane));
1441
    $this->commands[] = ajax_command_changed("#panel-pane-$pane->pid", "div.grab-title span.text");
1442
  }
1443

    
1444
  /**
1445
   * Create a command array to add a new pane.
1446
   */
1447
  function command_add_pane($pid) {
1448
    if (is_object($pid)) {
1449
      $pane = $pid;
1450
    }
1451
    else {
1452
      $pane = $this->display->content[$pid];
1453
    }
1454

    
1455
    $this->commands[] = ajax_command_append("#panel-region-$pane->panel", $this->render_pane($pane));
1456
    $this->commands[] = ajax_command_changed("#panel-pane-$pane->pid", "div.grab-title span.text");
1457
  }
1458

    
1459
  /**
1460
   * Create a command to update the links on a display after a change was made.
1461
   */
1462
  function command_update_display_links() {
1463
    $this->commands[] = ajax_command_replace('.panels-display-links', $this->get_display_links());
1464
  }
1465

    
1466
  /**
1467
   * Create a command to update the links on a region after a change was made.
1468
   */
1469
  function command_update_region_links($id) {
1470
    $this->commands[] = ajax_command_replace('.panels-region-links-' . $id, $this->get_region_links($id));
1471
  }
1472
}
1473

    
1474
/**
1475
 * Handle the 'next' click on the add/edit pane form wizard.
1476
 *
1477
 * All we need to do is store the updated pane in the cache.
1478
 */
1479
function panels_ajax_edit_pane_next(&$form_state) {
1480
  $form_state['display cache']->new_pane = $form_state['pane'];
1481
  panels_edit_cache_set($form_state['display cache']);
1482
}
1483

    
1484
/**
1485
 * Handle the 'finish' click on teh add/edit pane form wizard.
1486
 *
1487
 * All we need to do is set a flag so the return can handle adding
1488
 * the pane.
1489
 */
1490
function panels_ajax_edit_pane_finish(&$form_state) {
1491
  $form_state['complete'] = TRUE;
1492
  return;
1493
}
1494

    
1495
/**
1496
 * Handle the 'cancel' click on the add/edit pane form wizard.
1497
 */
1498
function panels_ajax_edit_pane_cancel(&$form_state) {
1499
  $form_state['cancel'] = TRUE;
1500
  return;
1501
}
1502

    
1503
// --------------------------------------------------------------------------
1504
// Forms for the editor object
1505

    
1506
/**
1507
 * Choose cache method form
1508
 */
1509
function panels_edit_cache_method_form($form, &$form_state) {
1510
  ctools_form_include($form_state, 'plugins', 'panels');
1511
  form_load_include($form_state, 'php', 'panels', '/plugins/display_renderers/panels_renderer_editor.class');
1512
  $display = &$form_state['display'];
1513
  $conf = &$form_state['conf'];
1514

    
1515
  // Set to 0 to ensure we get a selected radio.
1516
  if (!isset($conf['method'])) {
1517
    $conf['method'] = 0;
1518
  }
1519

    
1520
  $caches = panels_get_caches();
1521
  if (empty($caches)) {
1522
    $form['markup'] = array('#value' => t('No caching options are available at this time. Please enable a panels caching module in order to use caching options.'));
1523
    return $form;
1524
  }
1525

    
1526
  $options[0] = t('No caching');
1527
  foreach ($caches as $cache => $info) {
1528
    $options[$cache] = check_plain($info['title']);
1529
  }
1530

    
1531
  $form['method'] = array(
1532
    '#prefix' => '<div class="no-float">',
1533
    '#suffix' => '</div>',
1534
    '#type' => 'radios',
1535
    '#title' => t('Method'),
1536
    '#options' => $options,
1537
    '#default_value' => $conf['method'],
1538
  );
1539

    
1540
  $form['submit'] = array(
1541
    '#type' => 'submit',
1542
    '#value' => t('Next'),
1543
  );
1544
  return $form;
1545
}
1546

    
1547
/**
1548
 * Submit callback for panels_edit_cache_method_form.
1549
 *
1550
 * All this needs to do is return the method.
1551
 */
1552
function panels_edit_cache_method_form_submit($form, &$form_state) {
1553
  $form_state['method'] = $form_state['values']['method'];
1554
}
1555

    
1556
/**
1557
 * Cache settings form
1558
 */
1559
function panels_edit_cache_settings_form($form, &$form_state) {
1560
  ctools_form_include($form_state, 'plugins', 'panels');
1561
  form_load_include($form_state, 'php', 'panels', '/plugins/display_renderers/panels_renderer_editor.class');
1562
  $display = &$form_state['display'];
1563
  $conf = &$form_state['conf'];
1564
  $pid = $form_state['pid'];
1565
  $info = panels_get_cache($conf['method']);
1566

    
1567
  $form['#action'] = $form_state['url'];
1568

    
1569
  $form['description'] = array(
1570
    '#prefix' => '<div class="description">',
1571
    '#suffix' => '</div>',
1572
    '#value' => check_plain($info['description']),
1573
  );
1574

    
1575
  $function = panels_plugin_get_function('cache', $conf['method'], 'settings form');
1576

    
1577
  $form['settings'] = $function($conf['settings'], $display, $pid);
1578
  $form['settings']['#tree'] = TRUE;
1579

    
1580
  $form['display'] = array(
1581
    '#type' => 'value',
1582
    '#value' => $display,
1583
  );
1584

    
1585
  $form['pid'] = array(
1586
    '#type' => 'value',
1587
    '#value' => $pid,
1588
  );
1589

    
1590
  $form['submit'] = array(
1591
    '#type' => 'submit',
1592
    '#value' => t('Save'),
1593
  );
1594

    
1595
  return $form;
1596
}
1597

    
1598
/**
1599
 * Validate cache settings.
1600
 */
1601
function panels_edit_cache_settings_form_validate($form, &$form_state) {
1602
  if ($function = panels_plugin_get_function('cache', $form_state['conf']['method'], 'settings form validate')) {
1603
    $function($form, $form_state['values']['settings']);
1604
  }
1605
}
1606

    
1607
/**
1608
 * Allows panel styles to validate their style settings.
1609
 */
1610
function panels_edit_cache_settings_form_submit($form, &$form_state) {
1611
  if ($function = panels_plugin_get_function('cache', $form_state['conf']['method'], 'settings form submit')) {
1612
    $function($form_state['values']['settings']);
1613
  }
1614

    
1615
  $form_state['conf']['settings'] = $form_state['values']['settings'];
1616
}
1617

    
1618
/**
1619
 * Choose style form
1620
 */
1621
function panels_edit_style_type_form($form, &$form_state) {
1622
  ctools_form_include($form_state, 'plugins', 'panels');
1623
  form_load_include($form_state, 'php', 'panels', '/plugins/display_renderers/panels_renderer_editor.class');
1624
  $display = &$form_state['display'];
1625
  $style = $form_state['style'];
1626
  $type = $form_state['type'];
1627

    
1628
  $styles = panels_get_styles();
1629

    
1630
  $function = ($type == 'pane' ? 'render pane' : 'render region');
1631
  $options = array();
1632
  if ($type == 'region') {
1633
    $options[-1] = t('Use display default style');
1634
  }
1635

    
1636
  uasort($styles, 'ctools_plugin_sort');
1637

    
1638
  foreach ($styles as $id => $info) {
1639
    if (empty($info['hidden']) && (!empty($info[$function]) || $id == 'default')) {
1640
      $options[$id] = check_plain($info['title']);
1641
    }
1642
  }
1643

    
1644
  $form['style'] = array(
1645
    '#prefix' => '<div class="no-float">',
1646
    '#suffix' => '</div>',
1647
    '#type' => 'radios',
1648
    '#title' => t('Style'),
1649
    '#options' => $options,
1650
    '#default_value' => $style,
1651
  );
1652

    
1653
  $form['submit'] = array(
1654
    '#type' => 'submit',
1655
    '#value' => t('Next'),
1656
  );
1657
  return $form;
1658
}
1659

    
1660
/**
1661
 * Submit callback for panels_edit_style_type_form.
1662
 *
1663
 * All this needs to do is return the method.
1664
 */
1665
function panels_edit_style_type_form_submit($form, &$form_state) {
1666
  $form_state['old_style'] = $form_state['style'];
1667
  $form_state['style'] = $form_state['values']['style'];
1668
}
1669

    
1670
/**
1671
 * Style settings form
1672
 */
1673
function panels_edit_style_settings_form($form, &$form_state) {
1674
  ctools_form_include($form_state, 'plugins', 'panels');
1675
  form_load_include($form_state, 'php', 'panels', '/plugins/display_renderers/panels_renderer_editor.class');
1676
  $display = &$form_state['display'];
1677
  $conf = &$form_state['conf'];
1678
  $pid = $form_state['pid'];
1679
  $style = $form_state['style'];
1680
  $type = $form_state['type'];
1681

    
1682
  $form['#action'] = $form_state['url'];
1683

    
1684
  $form['description'] = array(
1685
    '#prefix' => '<div class="description">',
1686
    '#suffix' => '</div>',
1687
    '#value' => check_plain($style['description']),
1688
  );
1689

    
1690
  $function = panels_plugin_get_function('styles', $style, ($type == 'pane') ? 'pane settings form' : 'settings form');
1691

    
1692
  $form['settings'] = $function($conf, $display, $pid, $type, $form_state);
1693
  $form['settings']['#tree'] = TRUE;
1694

    
1695
  $form['submit'] = array(
1696
    '#type' => 'submit',
1697
    '#value' => t('Save'),
1698
  );
1699

    
1700
  return $form;
1701
}
1702

    
1703
/**
1704
 * Validate style settings.
1705
 */
1706
function panels_edit_style_settings_form_validate($form, &$form_state) {
1707
  $name = $form_state['type'] == 'pane' ? 'pane settings form validate' : 'settings form validate';
1708
  if ($function = panels_plugin_get_function('styles', $form_state['style'], $name)) {
1709
    $function($form, $form_state['values']['settings'], $form_state);
1710
  }
1711
}
1712

    
1713
/**
1714
 * Allows panel styles to validate their style settings.
1715
 */
1716
function panels_edit_style_settings_form_submit($form, &$form_state) {
1717
  $name = $form_state['type'] == 'pane' ? 'pane settings form submit' : 'settings form submit';
1718
  if ($function = panels_plugin_get_function('styles', $form_state['style'], $name)) {
1719
    $function($form, $form_state['values']['settings'], $form_state);
1720
  }
1721

    
1722
  $form_state['conf'] = $form_state['values']['settings'];
1723
}
1724

    
1725

    
1726
/**
1727
 * Configure CSS on a pane form.
1728
 */
1729
function panels_edit_configure_pane_css_form($form, &$form_state) {
1730
  ctools_form_include($form_state, 'plugins', 'panels');
1731
  form_load_include($form_state, 'php', 'panels', '/plugins/display_renderers/panels_renderer_editor.class');
1732
  $display = &$form_state['display'];
1733
  $pane = &$form_state['pane'];
1734

    
1735
  $form['css_id'] = array(
1736
    '#type' => 'textfield',
1737
    '#default_value' => isset($pane->css['css_id']) ? $pane->css['css_id'] : '',
1738
    '#title' => t('CSS ID'),
1739
    '#description' => t('CSS ID to apply to this pane. This may be blank.'),
1740
  );
1741
  $form['css_class'] = array(
1742
    '#type' => 'textfield',
1743
    '#default_value' => isset($pane->css['css_class']) ? $pane->css['css_class'] : '',
1744
    '#title' => t('CSS class'),
1745
    '#description' => t('CSS class to apply to this pane. This may be blank.'),
1746
  );
1747

    
1748
  $form['next'] = array(
1749
    '#type' => 'submit',
1750
    '#value' => t('Save'),
1751
  );
1752

    
1753
  return $form;
1754
}
1755

    
1756
/**
1757
 * FAPI submission function for the CSS configure form.
1758
 *
1759
 * All this does is set up $pane properly. The caller is responsible for
1760
 * actually storing this somewhere.
1761
 */
1762
function panels_edit_configure_pane_css_form_submit($form, &$form_state) {
1763
  $pane = &$form_state['pane'];
1764
  $display = $form_state['display'];
1765

    
1766
  $pane->css['css_id'] = $form_state['values']['css_id'];
1767
  $pane->css['css_class'] = $form_state['values']['css_class'];
1768
}
1769

    
1770
/**
1771
 * Configure lock on a pane form.
1772
 */
1773
function panels_edit_configure_pane_lock_form($form, &$form_state) {
1774
  ctools_form_include($form_state, 'plugins', 'panels');
1775
  form_load_include($form_state, 'php', 'panels', '/plugins/display_renderers/panels_renderer_editor.class');
1776
  $display = &$form_state['display'];
1777
  $pane = &$form_state['pane'];
1778

    
1779
  if (empty($pane->locks)) {
1780
    $pane->locks = array('type' => 'none', 'regions' => array());
1781
  }
1782

    
1783
  $form['type'] = array(
1784
    '#type' => 'radios',
1785
    '#title' => t('Lock type'),
1786
    '#options' => array(
1787
      'none' => t('No lock'),
1788
      'immovable' => t('Immovable'),
1789
      'regions' => t('Regions'),
1790
    ),
1791
    '#default_value' => $pane->locks['type'],
1792
  );
1793

    
1794
  $layout = panels_get_layout($display->layout);
1795
  $regions = panels_get_regions($layout, $display);
1796

    
1797
  $form['regions'] = array(
1798
    '#type' => 'checkboxes',
1799
    '#title' => t('Regions'),
1800
    '#options' => $regions,
1801
    '#description' => t('Select which regions this pane can be moved to.'),
1802
    '#dependency' => array(
1803
      'radio:type' => array('regions'),
1804
    ),
1805
    '#default_value' => $pane->locks['regions'],
1806
  );
1807

    
1808
  $form['#after_build'][] = 'panels_edit_configure_pane_lock_form_after_build';
1809
  $form['next'] = array(
1810
    '#type' => 'submit',
1811
    '#value' => t('Save'),
1812
  );
1813

    
1814
  return $form;
1815
}
1816

    
1817
function panels_edit_configure_pane_lock_form_after_build($element, $form_state) {
1818
  $region = $form_state['pane']->panel;
1819
  $element['regions'][$region]['#required'] = TRUE;
1820
  $element['regions'][$region]['#disabled'] = TRUE;
1821
  $element['regions'][$region]['#value'] = TRUE;
1822
  $element['regions'][$region]['#checked'] = TRUE;
1823
  $element['regions'][$region]['#attributes']['disabled'] = TRUE;
1824
  return $element;
1825
}
1826

    
1827
/**
1828
 * FAPI submission function for the lock configure form.
1829
 *
1830
 * All this does is set up $pane properly. The caller is responsible for
1831
 * actually storing this somewhere.
1832
 */
1833
function panels_edit_configure_pane_lock_form_submit($form, &$form_state) {
1834
  $pane = &$form_state['pane'];
1835
  $display = $form_state['display'];
1836

    
1837
  // We set this to true but forms do not submit disabled checkboxes
1838
  // and fapi is ignoring the #value directive probably because it
1839
  // is checkboxes:
1840
  $region = $form_state['pane']->panel;
1841
  $form_state['values']['regions'][$region] = $region;
1842

    
1843
  $pane->locks['type'] = $form_state['values']['type'];
1844
  $pane->locks['regions'] = array_filter($form_state['values']['regions']);
1845
}
1846

    
1847
/**
1848
 * Form to control basic visibility settings.
1849
 */
1850
function panels_edit_configure_access_settings_form($form, &$form_state) {
1851
  ctools_form_include($form_state, 'plugins', 'panels');
1852
  form_load_include($form_state, 'php', 'panels', '/plugins/display_renderers/panels_renderer_editor.class');
1853
  $display = &$form_state['display'];
1854
  $pane = &$form_state['pane'];
1855

    
1856
  $form['logic'] = array(
1857
    '#type' => 'radios',
1858
    '#options' => array(
1859
      'and' => t('All criteria must pass.'),
1860
      'or' => t('Only one criterion must pass.'),
1861
    ),
1862
    '#default_value' => isset($pane->access['logic']) ? $pane->access['logic'] : 'and',
1863
  );
1864

    
1865
  $form['next'] = array(
1866
    '#type' => 'submit',
1867
    '#value' => t('Save'),
1868
  );
1869

    
1870
  return $form;
1871
}
1872

    
1873
/**
1874
 * FAPI submission function for the edit access settings form.
1875
 *
1876
 * All this does is set up $pane properly. The caller is responsible for
1877
 * actually storing this somewhere.
1878
 */
1879
function panels_edit_configure_access_settings_form_submit($form, &$form_state) {
1880
  $pane = &$form_state['pane'];
1881
  $display = $form_state['display'];
1882

    
1883
  $pane->access['logic'] = $form_state['values']['logic'];
1884
}
1885

    
1886
/**
1887
 * Form to add a visibility rule.
1888
 */
1889
function panels_edit_add_access_test_form($form, &$form_state) {
1890
  ctools_form_include($form_state, 'plugins', 'panels');
1891
  form_load_include($form_state, 'php', 'panels', '/plugins/display_renderers/panels_renderer_editor.class');
1892
  $display = &$form_state['display'];
1893
  $pane = &$form_state['pane'];
1894

    
1895
  $plugins = ctools_get_relevant_access_plugins($display->context);
1896
  $options = array();
1897
  foreach ($plugins as $id => $plugin) {
1898
    $options[$id] = $plugin['title'];
1899
  }
1900

    
1901
  asort($options);
1902

    
1903
  $form['type'] = array(
1904
    // This ensures that the form item is added to the URL.
1905
    '#type' => 'radios',
1906
    '#options' => $options,
1907
  );
1908

    
1909
  $form['next'] = array(
1910
    '#type' => 'submit',
1911
    '#value' => t('Next'),
1912
  );
1913

    
1914
  return $form;
1915
}
1916

    
1917
/**
1918
 * Form to configure a visibility rule.
1919
 */
1920
function panels_edit_configure_access_test_form($form, &$form_state) {
1921
  ctools_form_include($form_state, 'plugins', 'panels');
1922
  form_load_include($form_state, 'php', 'panels', '/plugins/display_renderers/panels_renderer_editor.class');
1923
  $display = &$form_state['display'];
1924
  $test = &$form_state['test'];
1925
  $plugin = &$form_state['plugin'];
1926

    
1927
  $form['#action'] = $form_state['url'];
1928

    
1929
  $contexts = $display->context;
1930
  if (!isset($contexts['logged-in-user'])) {
1931
    $contexts['logged-in-user'] = ctools_access_get_loggedin_context();
1932
  }
1933

    
1934
  if (isset($plugin['required context'])) {
1935
    $form['context'] = ctools_context_selector($contexts, $plugin['required context'], $test['context']);
1936
  }
1937

    
1938
  $form['settings'] = array('#tree' => TRUE);
1939
  if ($function = ctools_plugin_get_function($plugin, 'settings form')) {
1940
    $form = $function($form, $form_state, $test['settings']);
1941
  }
1942

    
1943
  $form['not'] = array(
1944
    '#type' => 'checkbox',
1945
    '#title' => t('Reverse (NOT)'),
1946
    '#default_value' => !empty($test['not']),
1947
  );
1948

    
1949
  $form['save'] = array(
1950
    '#type' => 'submit',
1951
    '#value' => t('Save'),
1952
  );
1953

    
1954
  $form['remove'] = array(
1955
    '#type' => 'submit',
1956
    '#value' => t('Remove'),
1957
    '#remove' => TRUE,
1958
  );
1959

    
1960
  return $form;
1961
}
1962

    
1963
/**
1964
 * Validate handler for visibility rule settings
1965
 */
1966
function panels_edit_configure_access_test_form_validate(&$form, &$form_state) {
1967
  if (!empty($form_state['clicked_button']['#remove'])) {
1968
    return;
1969
  }
1970

    
1971
  if ($function = ctools_plugin_get_function($form_state['plugin'], 'settings form validate')) {
1972
    $function($form, $form_state);
1973
  }
1974
}
1975

    
1976
/**
1977
 * Submit handler for visibility rule settings
1978
 */
1979
function panels_edit_configure_access_test_form_submit(&$form, &$form_state) {
1980
  if (!empty($form_state['clicked_button']['#remove'])) {
1981
    $form_state['remove'] = TRUE;
1982
    return;
1983
  }
1984

    
1985
  if ($function = ctools_plugin_get_function($form_state['plugin'], 'settings form submit')) {
1986
    $function($form, $form_state);
1987
  }
1988

    
1989
  $form_state['test']['settings'] = $form_state['values']['settings'];
1990
  if (isset($form_state['values']['context'])) {
1991
    $form_state['test']['context'] = $form_state['values']['context'];
1992
  }
1993
  $form_state['test']['not'] = !empty($form_state['values']['not']);
1994
}
1995