Projet

Général

Profil

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

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

1
<?php
2

    
3
/**
4
 * @file
5
 * Class file to control the main Panels editor.
6
 */
7
class panels_renderer_editor extends panels_renderer_standard {
8

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

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

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

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

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

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

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

    
61
      ctools_add_js('panels-base', 'panels');
62
      ctools_add_js('display_editor', 'panels');
63
      ctools_add_css('panels_dnd', 'panels');
64
      ctools_add_css('panels_admin', 'panels');
65
      drupal_add_library('system', 'ui');
66
    }
67
  }
68

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

    
75
    $this->add_meta();
76

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

    
81
    return $output;
82
  }
83

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

    
90
    $content = implode('', $panes);
91

    
92
    $panel_buttons = $this->get_region_links($region_id);
93

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

    
100
    return $output;
101
  }
102

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

    
109
    ctools_include('content');
110
    $content_type = ctools_get_content_type($pane->type);
111

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

    
120
    $buttons = $this->get_pane_links($pane, $content_type);
121

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

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

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

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

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

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

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

    
161
    $output .= '<div class="' . $grabber_class . '">';
162
    if ($buttons) {
163
      $output .= '<span class="buttons">' . $buttons . '</span>';
164
    }
165
    $output .= '<span class="text" title="' . check_plain($title) . '">' . $title . '</span>';
166
    $output .= '</div>';
167
    // Grabber.
168
    $output .= '<div class="panel-pane-collapsible">';
169
    $output .= '<div class="pane-title">' . $block->title . '</div>';
170
    $output .= '<div class="pane-content">' . filter_xss_admin(render($block->content)) . '</div>';
171
    $output .= '</div>';
172
    // panel-pane-collapsible.
173
    $output .= '</div>';
174
    // panel-pane.
175
    return $output;
176
  }
177

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

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

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

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

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

    
210
    return $style_links;
211
  }
212

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

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

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

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

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

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

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

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

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

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

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

    
298
    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));
299
  }
300

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

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

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

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

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

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

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

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

    
368
      $visibility_links = array();
369

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

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

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

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

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

    
405
    if (user_access('use panels locks')) {
406
      $lock_type = !empty($pane->locks['type']) ? $pane->locks['type'] : 'none';
407
      switch ($lock_type) {
408
        case 'immovable':
409
          $lock_method = t('Immovable');
410
          break;
411

    
412
        case 'regions':
413
          $lock_method = t('Regions');
414
          break;
415

    
416
        case 'none':
417
        default:
418
          $lock_method = t('No lock');
419
          break;
420
      }
421

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

    
432
      $links['lock'] = $lock_links;
433
    }
434

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

    
456
      $links['cache'] = $cache_links;
457
    }
458

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

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

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

    
493
    $dropdown_links[] = array(
494
      'title' => '<hr />',
495
      'html' => TRUE,
496
    );
497
    $dropdown_links = array_merge($dropdown_links, $links['bottom']);
498

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

    
502
  // -----------------------------------------------------------------------
503
  // Display edit AJAX callbacks and helpers.
504
  /**
505
   * Generate a URL path for the AJAX editor.
506
   */
507
  function get_url() {
508
    $args = func_get_args();
509
    $command = array_shift($args);
510
    $url = 'panels/ajax/' . $this->plugin['name'] . '/' . $command . '/' . $this->display->cache_key;
511
    if ($args) {
512
      $url .= '/' . implode('/', $args);
513
    }
514

    
515
    return $url;
516
  }
517

    
518
  /**
519
   * Get the Panels storage oparation for a given renderer AJAX method.
520
   *
521
   * @param string $method
522
   *   The method name.
523
   *
524
   * @return string
525
   *   The Panels storage op.
526
   */
527
  function get_panels_storage_op_for_ajax($method) {
528
    switch ($method) {
529
      case 'ajax_show':
530
      case 'ajax_hide':
531
      case 'ajax_select_content':
532
      case 'ajax_add_pane':
533
      case 'ajax_edit_pane':
534
      case 'ajax_panel_title':
535
      case 'ajax_cache_method':
536
      case 'ajax_cache_settings':
537
      case 'ajax_style_type':
538
      case 'ajax_style_settings':
539
      case 'ajax_pane_css':
540
      case 'ajax_lock':
541
      case 'ajax_access_settings':
542
      case 'ajax_access_add_test':
543
      case 'ajax_access_configure_test':
544
      case 'ajax_layout':
545
      case 'ajax_style':
546
        return 'update';
547
    }
548

    
549
    return parent::get_panels_storage_op_for_ajax($method);
550
  }
551

    
552
  /**
553
   * AJAX command to show a pane.
554
   */
555
  function ajax_show($pid = NULL) {
556
    if (empty($this->display->content[$pid])) {
557
      ctools_ajax_render_error(t('Invalid pane id.'));
558
    }
559

    
560
    $this->display->content[$pid]->shown = TRUE;
561
    panels_edit_cache_set($this->cache);
562

    
563
    $this->command_update_pane($pid);
564
  }
565

    
566
  /**
567
   * AJAX command to show a pane.
568
   */
569
  function ajax_hide($pid = NULL) {
570
    if (empty($this->display->content[$pid])) {
571
      ctools_ajax_render_error(t('Invalid pane id.'));
572
    }
573

    
574
    $this->display->content[$pid]->shown = FALSE;
575
    panels_edit_cache_set($this->cache);
576

    
577
    $this->command_update_pane($pid);
578
  }
579

    
580
  /**
581
   * AJAX command to present a dialog with a list of available content.
582
   */
583
  function ajax_select_content($region = NULL, $category = NULL) {
584
    if (!array_key_exists($region, $this->plugins['layout']['regions'])) {
585
      ctools_modal_render(t('Error'), t('Invalid input'));
586
    }
587

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

    
590
    $categories = $this->get_categories($this->cache->content_types);
591

    
592
    if (empty($categories)) {
593
      $output = t('There are no content types you may add to this display.');
594
    }
595
    else {
596
      $output = theme('panels_add_content_modal', array('renderer' => $this, 'categories' => $categories, 'category' => $category, 'region' => $region));
597
    }
598
    $this->commands[] = ctools_modal_command_display($title, $output);
599

    
600
    // Give keybord focus to the first item in the category we just loaded.
601
    if (!empty($category)) {
602
      $this->commands[] = ajax_command_invoke(".panels-add-content-modal .panels-section-columns :focusable:first", 'focus');
603
    }
604
  }
605

    
606
  /**
607
   * Return the category name and the category key of a given content
608
   * type.
609
   *
610
   * @todo -- this should be in CTools.
611
   */
612
  function get_category($content_type) {
613
    if (!empty($content_type['top level'])) {
614
      $category = 'root';
615
    }
616
    elseif (isset($content_type['category'])) {
617
      if (is_array($content_type['category'])) {
618
        list($category, $weight) = $content_type['category'];
619
      }
620
      else {
621
        $category = $content_type['category'];
622
      }
623
    }
624
    else {
625
      $category = t('Uncategorized');
626
    }
627

    
628
    return array(preg_replace('/[^a-z0-9]/', '-', strtolower($category)), $category);
629
  }
630

    
631

    
632
  /**
633
   * Create a list of categories from all of the content type.
634
   *
635
   * @return array
636
   *   An array of categories. Each entry in the array will also be an array
637
   *   with 'title' as the printable title of the category, and 'content'
638
   *   being an array of all content in the category. Each item in the 'content'
639
   *   array contain the array plugin definition so that it can be later
640
   *   found in the content array. They will be keyed by the title so that they
641
   *   can be sorted.
642
   */
643
  function get_categories($content_types) {
644
    $categories = array();
645
    $category_names = array();
646

    
647
    foreach ($content_types as $type_name => $subtypes) {
648
      foreach ($subtypes as $subtype_name => $content_type) {
649
        list($category_key, $category) = $this->get_category($content_type);
650

    
651
        if (empty($categories[$category_key])) {
652
          $categories[$category_key] = array(
653
            'title' => $category,
654
            'content' => array(),
655
          );
656
          $category_names[$category_key] = $category;
657
        }
658

    
659
        $content_title = filter_xss_admin($content_type['title']);
660

    
661
        // Ensure content with the same title doesn't overwrite each other.
662
        while (isset($categories[$category_key]['content'][$content_title])) {
663
          $content_title .= '-';
664
        }
665

    
666
        $categories[$category_key]['content'][$content_title] = $content_type;
667
        $categories[$category_key]['content'][$content_title]['type_name'] = $type_name;
668
        $categories[$category_key]['content'][$content_title]['subtype_name'] = $subtype_name;
669
      }
670
    }
671

    
672
    // Now sort.
673
    natcasesort($category_names);
674
    foreach ($category_names as $category => $name) {
675
      $output[$category] = $categories[$category];
676
    }
677

    
678
    return $output;
679
  }
680

    
681
  /**
682
   * AJAX entry point to add a new pane.
683
   */
684
  function ajax_add_pane($region = NULL, $type_name = NULL, $subtype_name = NULL, $step = NULL) {
685
    $content_type = ctools_get_content_type($type_name);
686
    $subtype = ctools_content_get_subtype($content_type, $subtype_name);
687

    
688
    // Determine if we are adding a different pane than previously cached. This
689
    // is used to load the different pane into cache so that multistep forms
690
    // have the correct context instead of a previously cached version that
691
    // does not match the pane currently being added.
692
    $is_different_pane = FALSE;
693
    if (isset($this->cache) && isset($this->cache->new_pane)) {
694
      $diff_type = $type_name != $this->cache->new_pane->type;
695
      $diff_subtype = $subtype_name != $this->cache->new_pane->subtype;
696

    
697
      $is_different_pane = $diff_type || $diff_subtype;
698
    }
699

    
700
    if (!isset($step) || !isset($this->cache->new_pane) || $is_different_pane) {
701
      $pane = panels_new_pane($type_name, $subtype_name, TRUE);
702
      $this->cache->new_pane = &$pane;
703
    }
704
    else {
705
      $pane = &$this->cache->new_pane;
706
    }
707

    
708
    $form_state = array(
709
      'display' => &$this->cache->display,
710
      'contexts' => $this->cache->display->context,
711
      'pane' => &$pane,
712
      'cache_key' => $this->display->cache_key,
713
      'display cache' => &$this->cache,
714
      'ajax' => TRUE,
715
      'modal' => TRUE,
716
      // This will force the system to not automatically render.
717
      'modal return' => TRUE,
718
      'commands' => array(),
719
    );
720

    
721
    $form_info = array(
722
      'path' => $this->get_url('add-pane', $region, $type_name, $subtype_name, '%step'),
723
      'show cancel' => TRUE,
724
      'next callback' => 'panels_ajax_edit_pane_next',
725
      'finish callback' => 'panels_ajax_edit_pane_finish',
726
      'cancel callback' => 'panels_ajax_edit_pane_cancel',
727
    );
728

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

    
731
    // If $rc is FALSE, there was no actual form.
732
    if ($output === FALSE || !empty($form_state['complete'])) {
733
      // References get blown away with AJAX caching. This will fix that.
734
      $pane = $form_state['pane'];
735
      unset($this->cache->new_pane);
736

    
737
      // Add the pane to the display.
738
      $this->display->add_pane($pane, $region);
739
      panels_edit_cache_set($this->cache);
740

    
741
      // Tell the client to draw the pane.
742
      $this->command_add_pane($pane);
743

    
744
      // Dismiss the modal.
745
      $this->commands[] = ctools_modal_command_dismiss();
746
    }
747
    elseif (!empty($form_state['cancel'])) {
748
      // If cancelling, return to the activity.
749
      list($category_key, $category) = $this->get_category($subtype);
750
      $this->ajax_select_content($region, $category_key);
751
    }
752
    else {
753
      // This overwrites any previous commands.
754
      $this->commands = ctools_modal_form_render($form_state, $output);
755
    }
756
  }
757

    
758
  /**
759
   * AJAX entry point to edit a pane.
760
   */
761
  function ajax_edit_pane($pid = NULL, $step = NULL) {
762
    if (empty($this->cache->display->content[$pid])) {
763
      ctools_modal_render(t('Error'), t('Invalid pane id.'));
764
    }
765

    
766
    $pane = &$this->cache->display->content[$pid];
767

    
768
    $content_type = ctools_get_content_type($pane->type);
769
    $subtype = ctools_content_get_subtype($content_type, $pane->subtype);
770

    
771
    $form_state = array(
772
      'display' => &$this->cache->display,
773
      'contexts' => $this->cache->display->context,
774
      'pane' => &$pane,
775
      'display cache' => &$this->cache,
776
      'ajax' => TRUE,
777
      'modal' => TRUE,
778
      'modal return' => TRUE,
779
      'commands' => array(),
780
    );
781

    
782
    $form_info = array(
783
      'path' => $this->get_url('edit-pane', $pid, '%step'),
784
      'show cancel' => TRUE,
785
      'next callback' => 'panels_ajax_edit_pane_next',
786
      'finish callback' => 'panels_ajax_edit_pane_finish',
787
      'cancel callback' => 'panels_ajax_edit_pane_cancel',
788
    );
789

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

    
792
    // If $rc is FALSE, there was no actual form.
793
    if ($output === FALSE || !empty($form_state['cancel'])) {
794
      // Dismiss the modal.
795
      $this->commands[] = ctools_modal_command_dismiss();
796
    }
797
    elseif (!empty($form_state['complete'])) {
798
      // References get blown away with AJAX caching. This will fix that.
799
      $this->cache->display->content[$pid] = $form_state['pane'];
800

    
801
      // Conditionally overwrite the context for this panel if present in the form state.
802
      if (!empty($form_state['display_cache']->display->context)) {
803
        $this->cache->display->context = $form_state['display_cache']->display->context;
804
      }
805

    
806
      panels_edit_cache_set($this->cache);
807
      $this->command_update_pane($pid);
808
      $this->commands[] = ctools_modal_command_dismiss();
809
    }
810
    else {
811
      // This overwrites any previous commands.
812
      $this->commands = ctools_modal_form_render($form_state, $output);
813
    }
814
  }
815

    
816
  /**
817
   * AJAX entry point to select which pane is currently the title.
818
   *
819
   * @param string $pid
820
   *   The pane id for the pane object whose title state we're setting.
821
   */
822
  function ajax_panel_title($pid = NULL) {
823
    if (empty($this->display->content[$pid])) {
824
      ctools_ajax_render_error(t('Invalid pane id.'));
825
    }
826

    
827
    $pane = &$this->display->content[$pid];
828

    
829
    $old_title = !empty($this->display->title_pane) ? $this->display->title_pane : NULL;
830
    $this->display->title_pane = $pid;
831

    
832
    panels_edit_cache_set($this->cache);
833

    
834
    $this->command_update_pane($pane);
835

    
836
    if ($old_title && !empty($this->cache->display->content[$old_title])) {
837
      $this->command_update_pane($this->cache->display->content[$old_title]);
838
    }
839
  }
840

    
841
  /**
842
   * AJAX entry point to configure the cache method for a pane or the display.
843
   *
844
   * @param string $pid
845
   *   Either a pane id for a pane in the display, or 'display' to edit the
846
   *   display cache settings.
847
   */
848
  function ajax_cache_method($pid = NULL) {
849
    ctools_include('content');
850
    // This lets us choose whether we're doing the display's cache or
851
    // a pane's.
852
    if ($pid == 'display') {
853
      $conf = &$this->display->cache;
854
      $title = t('Cache method for this display');
855
    }
856
    elseif (!empty($this->display->content[$pid])) {
857
      $pane = &$this->display->content[$pid];
858
      $subtype = ctools_content_get_subtype($pane->type, $pane->subtype);
859
      $conf = &$pane->cache;
860
      $title = t('Cache method for !subtype_title', array('!subtype_title' => $subtype['title']));
861
    }
862
    else {
863
      ctools_modal_render(t('Error'), t('Invalid pane id.'));
864
    }
865

    
866
    $form_state = array(
867
      'display' => &$this->display,
868
      'conf' => &$conf,
869
      'title' => $title,
870
      'ajax' => TRUE,
871
    );
872

    
873
    $output = ctools_modal_form_wrapper('panels_edit_cache_method_form', $form_state);
874
    if (empty($form_state['executed'])) {
875
      $this->commands = $output;
876
      return;
877
    }
878

    
879
    // Preserve this; this way we don't actually change the method until they
880
    // have saved the form.
881
    $info = panels_get_cache($form_state['method']);
882
    $function = panels_plugin_get_function('cache', $info, 'settings form');
883
    if (!$function) {
884
      $conf['method'] = $form_state['method'];
885
      $conf['settings'] = array();
886
      panels_edit_cache_set($this->cache);
887

    
888
      $this->commands[] = ctools_modal_command_dismiss();
889

    
890
      if ($pid != 'display') {
891
        $this->command_update_pane($pane);
892
      }
893
      else {
894
        $this->command_update_display_links();
895
      }
896
    }
897
    else {
898
      $this->cache->method = $form_state['method'];
899
      panels_edit_cache_set($this->cache);
900
      // Send them to next form.
901
      return $this->ajax_cache_settings($pid);
902
    }
903
  }
904

    
905
  /**
906
   * AJAX entry point to configure the cache settings for a pane or the display.
907
   *
908
   * @param string $pid
909
   *   Either a pane id for a pane in the display, or 'display' to edit the
910
   *   display cache settings.
911
   */
912
  function ajax_cache_settings($pid = 0) {
913
    ctools_include('content');
914

    
915
    // This lets us choose whether we're doing the display's cache or
916
    // a pane's.
917
    if ($pid == 'display') {
918
      $conf = &$this->display->cache;
919
      $title = t('Cache settings for this display');
920
    }
921
    elseif (!empty($this->display->content[$pid])) {
922
      $pane = &$this->display->content[$pid];
923
      $subtype = ctools_content_get_subtype($pane->type, $pane->subtype);
924

    
925
      $conf = &$pane->cache;
926
      $title = t('Cache settings for !subtype_title', array('!subtype_title' => $subtype['title']));
927
    }
928
    else {
929
      ctools_modal_render(t('Error'), t('Invalid pane id.'));
930
    }
931

    
932
    if (isset($this->cache->method) && (empty($conf['method']) || $conf['method'] != $this->cache->method)) {
933
      $conf['method'] = $this->cache->method;
934
      $info = panels_get_cache($conf['method']);
935
      $conf['settings'] = isset($info['defaults']) ? $info['defaults'] : array();
936
    }
937

    
938
    $form_state = array(
939
      'display' => &$this->display,
940
      'pid' => $pid,
941
      'conf' => &$conf,
942
      'ajax' => TRUE,
943
      'title' => $title,
944
      'url' => url($this->get_url('cache-settings', $pid), array('absolute' => TRUE)),
945
    );
946

    
947
    $output = ctools_modal_form_wrapper('panels_edit_cache_settings_form', $form_state);
948
    if (empty($form_state['executed'])) {
949
      $this->commands = $output;
950
      return;
951
    }
952

    
953
    panels_edit_cache_set($this->cache);
954

    
955
    $this->commands[] = ctools_modal_command_dismiss();
956

    
957
    if ($pid != 'display') {
958
      $this->command_update_pane($pane);
959
    }
960
    else {
961
      $this->command_update_display_links();
962
    }
963
  }
964

    
965
  /**
966
   * AJAX entry point to select the style for a display, region or pane.
967
   *
968
   * @param string $type
969
   *   Either display, region or pane
970
   * @param $pid
971
   *   The pane id, if a pane. The region id, if a region.
972
   */
973
  function ajax_style_type($type, $pid = NULL) {
974
    // This lets us choose whether we're doing the display's cache or
975
    // a pane's.
976
    switch ($type) {
977
      case 'display':
978
        $style = isset($this->display->panel_settings['style']) ? $this->display->panel_settings['style'] : 'default';
979
        $title = t('Default style for this display');
980
        break;
981

    
982
      case 'region':
983
        $style = isset($this->display->panel_settings[$pid]['style']) ? $this->display->panel_settings[$pid]['style'] : '-1';
984
        // -1 signifies to use the default setting.
985
        $title = t('Panel style for region "!region"', array('!region' => $this->plugins['layout']['regions'][$pid]));
986
        break;
987

    
988
      case 'pane':
989
        ctools_include('content');
990
        $pane = &$this->display->content[$pid];
991
        $style = isset($pane->style['style']) ? $pane->style['style'] : 'default';
992
        $title = ctools_content_admin_title($pane->type, $pane->subtype, $pane->configuration, $this->display->context);
993
        if (!$title) {
994
          $title = $pane->type;
995
        }
996
        $title = t('Pane style for "!title"', array('!title' => $title));
997
        break;
998

    
999
      default:
1000
        ctools_modal_render(t('Error'), t('Invalid pane id.'));
1001
    }
1002
    $info = $this->get_style($type, $pid);
1003
    $style_plugin = $info[0];
1004
    $style_settings = $info[1];
1005

    
1006
    // Backward compatibility: Translate old-style stylizer to new style
1007
    // stylizer.
1008
    if ($style == 'stylizer' && !empty($style_settings['style']) && $style_settings['style'] != '$') {
1009
      $style = 'stylizer:' . $style_settings['style'];
1010
    }
1011

    
1012
    $form_state = array(
1013
      'display' => &$this->display,
1014
      'style' => $style,
1015
      'pane' => ($type == 'pane') ? $this->display->content[$pid] : NULL,
1016
      'title' => $title,
1017
      'ajax' => TRUE,
1018
      'type' => $type,
1019
    );
1020

    
1021
    $output = ctools_modal_form_wrapper('panels_edit_style_type_form', $form_state);
1022
    if (empty($form_state['executed'])) {
1023
      $this->commands = $output;
1024
      return;
1025
    }
1026

    
1027
    // Preserve this; this way we don't actually change the method until they
1028
    // have saved the form.
1029
    $style = panels_get_style($form_state['style']);
1030
    $function = panels_plugin_get_function('styles', $style, ($type == 'pane') ? 'pane settings form' : 'settings form');
1031
    if (!$function) {
1032
      if (isset($this->cache->style)) {
1033
        unset($this->cache->style);
1034
      }
1035

    
1036
      // If there's no settings form, just change the style and exit.
1037
      switch ($type) {
1038
        case 'display':
1039
          $this->display->panel_settings['style'] = $form_state['style'];
1040
          if (isset($this->display->panel_settings['style_settings']['default'])) {
1041
            unset($this->display->panel_settings['style_settings']['default']);
1042
          }
1043
          break;
1044

    
1045
        case 'region':
1046
          $this->display->panel_settings[$pid]['style'] = $form_state['style'];
1047
          if (isset($this->display->panel_settings['style_settings'][$pid])) {
1048
            unset($this->display->panel_settings['style_settings'][$pid]);
1049
          }
1050
          break;
1051

    
1052
        case 'pane':
1053
          $pane->style['style'] = $form_state['style'];
1054
          if (isset($pane->style['settings'])) {
1055
            unset($pane->style['settings']);
1056
          }
1057

    
1058
          break;
1059
      }
1060
      panels_edit_cache_set($this->cache);
1061

    
1062
      $this->commands[] = ctools_modal_command_dismiss();
1063

    
1064
      if ($type == 'pane') {
1065
        $this->command_update_pane($pane);
1066
      }
1067
      elseif ($type == 'region') {
1068
        $this->command_update_region_links($pid);
1069
      }
1070
      else {
1071
        $this->command_update_display_links();
1072
      }
1073
    }
1074
    else {
1075
      if ($form_state['style'] != $form_state['old_style']) {
1076
        $this->cache->style = $form_state['style'];
1077
        panels_edit_cache_set($this->cache);
1078
      }
1079

    
1080
      // Send them to next form.
1081
      return $this->ajax_style_settings($type, $pid);
1082
    }
1083
  }
1084

    
1085
  /**
1086
   * Get the appropriate style from the panel in the cache.
1087
   *
1088
   * Since we have styles for regions, panes and the display itself, and
1089
   * they are stored differently, we use this method to simplify getting
1090
   * style information into a way that's easy to cope with.
1091
   */
1092
  function get_style($type, $pid = '') {
1093
    if (isset($this->cache->style)) {
1094
      $style = panels_get_style($this->cache->style);
1095
      $defaults = isset($style['defaults']) ? $style['defaults'] : array();
1096
      // Get the &$conf variable based upon whose style we're editing.
1097
      switch ($type) {
1098
        case 'display':
1099
          $this->display->panel_settings['style'] = $this->cache->style;
1100
          $this->display->panel_settings['style_settings']['default'] = $defaults;
1101
          break;
1102

    
1103
        case 'region':
1104
          $this->display->panel_settings[$pid]['style'] = $this->cache->style;
1105
          $this->display->panel_settings['style_settings'][$pid] = $defaults;
1106
          break;
1107

    
1108
        case 'pane':
1109
          $pane = &$this->display->content[$pid];
1110
          $pane->style['style'] = $this->cache->style;
1111
          $pane->style['settings'] = $defaults;
1112
          $conf = &$pane->style['settings'];
1113
          break;
1114
      }
1115
    }
1116
    else {
1117
      switch ($type) {
1118
        case 'display':
1119
          $style = panels_get_style((!empty($this->display->panel_settings['style'])) ? $this->display->panel_settings['style'] : 'default');
1120
          break;
1121

    
1122
        case 'region':
1123
          $style = panels_get_style((!empty($this->display->panel_settings[$pid]['style'])) ? $this->display->panel_settings[$pid]['style'] : '-1');
1124
          break;
1125

    
1126
        case 'pane':
1127
          $pane = &$this->display->content[$pid];
1128
          $style = panels_get_style(!empty($pane->style['style']) ? $pane->style['style'] : 'default');
1129
          break;
1130
      }
1131
    }
1132

    
1133
    // Set up our $conf reference.
1134
    switch ($type) {
1135
      case 'display':
1136
        $conf = &$this->display->panel_settings['style_settings']['default'];
1137
        break;
1138

    
1139
      case 'region':
1140
        $conf = &$this->display->panel_settings['style_settings'][$pid];
1141
        break;
1142

    
1143
      case 'pane':
1144
        ctools_include('content');
1145
        $pane = &$this->display->content[$pid];
1146
        $conf = &$pane->style['settings'];
1147
        break;
1148
    }
1149

    
1150
    // Backward compatibility: Translate old-style stylizer to new style
1151
    // stylizer.
1152
    if ($style['name'] == 'stylizer' && !empty($conf['style']) && $conf['style'] != '$') {
1153
      $style = panels_get_style('stylizer:' . $conf['style']);
1154
    }
1155

    
1156
    return array($style, &$conf);
1157
  }
1158

    
1159
  /**
1160
   * AJAX entry point to configure the style for a display, region or pane.
1161
   *
1162
   * @param string $type
1163
   *   Either display, region or pane
1164
   * @param $pid
1165
   *   The pane id, if a pane. The region id, if a region.
1166
   */
1167
  function ajax_style_settings($type, $pid = '') {
1168
    $info = $this->get_style($type, $pid);
1169
    $style = $info[0];
1170
    $conf = &$info[1];
1171

    
1172
    switch ($type) {
1173
      case 'display':
1174
        $title = t('Style settings for @style (display)', array('@style' => $style['title']));
1175
        break;
1176

    
1177
      case 'region':
1178
        $title = t('Style settings for style @style (Region "!region")', array('@style' => $style['title'], '!region' => $this->plugins['layout']['regions'][$pid]));
1179
        break;
1180

    
1181
      case 'pane':
1182
        ctools_include('content');
1183
        $pane = &$this->display->content[$pid];
1184
        $subtype = ctools_content_get_subtype($pane->type, $pane->subtype);
1185
        $title = t('Style settings for style @style (Pane "!pane")', array('@style' => $style['title'], '!pane' => $subtype['title']));
1186
        break;
1187
    }
1188

    
1189
    $form_state = array(
1190
      'display' => &$this->display,
1191
      'type' => $type,
1192
      'pid' => $pid,
1193
      'conf' => &$conf,
1194
      'style' => $style,
1195
      'ajax' => TRUE,
1196
      'title' => $title,
1197
      'url' => url($this->get_url('style-settings', $type, $pid), array('absolute' => TRUE)),
1198
      'renderer' => &$this,
1199
    );
1200

    
1201
    $output = ctools_modal_form_wrapper('panels_edit_style_settings_form', $form_state);
1202
    if (empty($form_state['executed'])) {
1203
      $this->commands = $output;
1204
      return;
1205
    }
1206

    
1207
    if (isset($this->cache->style)) {
1208
      unset($this->cache->style);
1209
    }
1210

    
1211
    if (!empty($form_state['cancel'])) {
1212
      // The cache must be saved prior to dismissing the modal.
1213
      panels_edit_cache_set($this->cache);
1214
      $this->commands[] = ctools_modal_command_dismiss();
1215
      return;
1216
    }
1217

    
1218
    // Copy settings from form state back into the cache.
1219
    if (!empty($form_state['values']['settings'])) {
1220
      if ($type == 'pane') {
1221
        $this->cache->display->content[$pid]->style['settings'] = $form_state['values']['settings'];
1222
      }
1223
      elseif ($type == 'region') {
1224
        $this->cache->display->panel_settings['style_settings'][$pid] = $form_state['values']['settings'];
1225
      }
1226
    }
1227

    
1228
    panels_edit_cache_set($this->cache);
1229

    
1230
    $this->commands[] = ctools_modal_command_dismiss();
1231

    
1232
    if ($type == 'pane') {
1233
      $this->command_update_pane($pane);
1234
    }
1235
    elseif ($type == 'region') {
1236
      $this->command_update_region_links($pid);
1237
    }
1238
    else {
1239
      $this->command_update_display_links();
1240
    }
1241
  }
1242

    
1243
  /**
1244
   * AJAX entry point to configure CSS for a pane.
1245
   *
1246
   * @param $pid
1247
   *   The pane id to edit.
1248
   */
1249
  function ajax_pane_css($pid = NULL) {
1250
    if (empty($this->display->content[$pid])) {
1251
      ctools_modal_render(t('Error'), t('Invalid pane id.'));
1252
    }
1253

    
1254
    $pane = &$this->display->content[$pid];
1255
    $subtype = ctools_content_get_subtype($pane->type, $pane->subtype);
1256

    
1257
    $form_state = array(
1258
      'display' => &$this->display,
1259
      'pane' => &$pane,
1260
      'ajax' => TRUE,
1261
      'title' => t('Configure CSS on !subtype_title', array('!subtype_title' => $subtype['title'])),
1262
    );
1263

    
1264
    $output = ctools_modal_form_wrapper('panels_edit_configure_pane_css_form', $form_state);
1265
    if (empty($form_state['executed'])) {
1266
      $this->commands = $output;
1267
      return;
1268
    }
1269

    
1270
    panels_edit_cache_set($this->cache);
1271
    $this->command_update_pane($pid);
1272
    $this->commands[] = ctools_modal_command_dismiss();
1273
  }
1274

    
1275
  /**
1276
   * AJAX entry point to configure CSS for a pane.
1277
   *
1278
   * @param $pid
1279
   *   The pane id to edit.
1280
   */
1281
  function ajax_lock($pid = NULL) {
1282
    if (empty($this->display->content[$pid])) {
1283
      ctools_modal_render(t('Error'), t('Invalid pane id.'));
1284
    }
1285

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

    
1289
    $form_state = array(
1290
      'display' => &$this->display,
1291
      'pane' => &$pane,
1292
      'ajax' => TRUE,
1293
      'title' => t('Configure lock on !subtype_title', array('!subtype_title' => $subtype['title'])),
1294
    );
1295

    
1296
    $output = ctools_modal_form_wrapper('panels_edit_configure_pane_lock_form', $form_state);
1297
    if (empty($form_state['executed'])) {
1298
      $this->commands = $output;
1299
      return;
1300
    }
1301

    
1302
    panels_edit_cache_set($this->cache);
1303
    $this->command_update_pane($pid);
1304
    $this->commands[] = ctools_modal_command_dismiss();
1305
  }
1306

    
1307
  /**
1308
   * AJAX entry point to configure access settings for a pane.
1309
   *
1310
   * @param $pid
1311
   *   The pane id to edit.
1312
   */
1313
  function ajax_access_settings($pid = NULL) {
1314
    if (empty($this->display->content[$pid])) {
1315
      ctools_modal_render(t('Error'), t('Invalid pane id.'));
1316
    }
1317

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

    
1321
    $form_state = array(
1322
      'display' => &$this->display,
1323
      'pane' => &$pane,
1324
      'ajax' => TRUE,
1325
      'title' => t('Access settings on !subtype_title', array('!subtype_title' => $subtype['title'])),
1326
    );
1327

    
1328
    $output = ctools_modal_form_wrapper('panels_edit_configure_access_settings_form', $form_state);
1329
    if (empty($form_state['executed'])) {
1330
      $this->commands = $output;
1331
      return;
1332
    }
1333

    
1334
    panels_edit_cache_set($this->cache);
1335
    $this->command_update_pane($pid);
1336
    $this->commands[] = ctools_modal_command_dismiss();
1337
  }
1338

    
1339
  /**
1340
   * AJAX entry point for to add a visibility rule.
1341
   */
1342
  function ajax_access_add_test($pid = NULL) {
1343
    if (empty($this->display->content[$pid])) {
1344
      ctools_modal_render(t('Error'), t('Invalid pane id.'));
1345
    }
1346

    
1347
    $pane = &$this->display->content[$pid];
1348
    $subtype = ctools_content_get_subtype($pane->type, $pane->subtype);
1349

    
1350
    $form_state = array(
1351
      'display' => &$this->display,
1352
      'pane' => &$pane,
1353
      'ajax' => TRUE,
1354
      'title' => t('Add visibility rule for !subtype_title', array('!subtype_title' => $subtype['title'])),
1355
    );
1356

    
1357
    $output = ctools_modal_form_wrapper('panels_edit_add_access_test_form', $form_state);
1358
    if (!empty($form_state['executed'])) {
1359
      // Set up the plugin in cache.
1360
      $plugin = ctools_get_access_plugin($form_state['values']['type']);
1361
      $this->cache->new_plugin = ctools_access_new_test($plugin);
1362
      panels_edit_cache_set($this->cache);
1363

    
1364
      // Go to the next step.
1365
      return $this->ajax_access_configure_test($pid, 'add');
1366
    }
1367

    
1368
    $this->commands = $output;
1369
  }
1370

    
1371
  /**
1372
   * AJAX entry point for to configure vsibility rule.
1373
   */
1374
  function ajax_access_configure_test($pid = NULL, $id = NULL) {
1375
    if (empty($this->display->content[$pid])) {
1376
      ctools_modal_render(t('Error'), t('Invalid pane id.'));
1377
    }
1378

    
1379
    $pane = &$this->display->content[$pid];
1380
    $subtype = ctools_content_get_subtype($pane->type, $pane->subtype);
1381

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

    
1385
    // If we're adding a new one, get the stored data from cache and
1386
    // add it. It's stored as a cache so that if this is closed
1387
    // we don't accidentally add an unconfigured plugin.
1388
    if ($id == 'add') {
1389
      $pane->access['plugins'][] = $this->cache->new_plugin;
1390
      $id = max(array_keys($pane->access['plugins']));
1391
    }
1392
    elseif (empty($pane->access['plugins'][$id])) {
1393
      ctools_modal_render(t('Error'), t('Invalid test id.'));
1394
    }
1395

    
1396
    $form_state = array(
1397
      'display' => &$this->display,
1398
      'pane' => &$pane,
1399
      'ajax' => TRUE,
1400
      'title' => t('Configure visibility rule for !subtype_title', array('!subtype_title' => $subtype['title'])),
1401
      'test' => &$pane->access['plugins'][$id],
1402
      'plugin' => ctools_get_access_plugin($pane->access['plugins'][$id]['name']),
1403
      'url' => url($url, array('absolute' => TRUE)),
1404
    );
1405

    
1406
    $output = ctools_modal_form_wrapper('panels_edit_configure_access_test_form', $form_state);
1407
    if (empty($form_state['executed'])) {
1408
      $this->commands = $output;
1409
      return;
1410
    }
1411

    
1412
    // Unset the new plugin.
1413
    if (isset($this->cache->new_plugin)) {
1414
      unset($this->cache->new_plugin);
1415
    }
1416

    
1417
    if (!empty($form_state['remove'])) {
1418
      unset($pane->access['plugins'][$id]);
1419
    }
1420

    
1421
    panels_edit_cache_set($this->cache);
1422
    $this->command_update_pane($pid);
1423
    $this->commands[] = ctools_modal_command_dismiss();
1424
  }
1425

    
1426
  /**
1427
   * AJAX Router function for layout owned AJAX calls.
1428
   *
1429
   * Layouts like the flexible layout builder need callbacks of their own.
1430
   * This allows those layouts to simply declare their callbacks and use
1431
   * them with $this->get_url('layout', $command).
1432
   */
1433
  function ajax_layout() {
1434
    $args = func_get_args();
1435
    if (empty($args)) {
1436
      return MENU_NOT_FOUND;
1437
    }
1438

    
1439
    $command = array_shift($args);
1440
    if (empty($this->plugins['layout']['ajax'][$command]) || !function_exists($this->plugins['layout']['ajax'][$command])) {
1441
      return MENU_NOT_FOUND;
1442
    }
1443

    
1444
    // Make sure the this is always available to the called functions.
1445
    array_unshift($args, $this);
1446
    return call_user_func_array($this->plugins['layout']['ajax'][$command], $args);
1447
  }
1448

    
1449
  /**
1450
   * AJAX Router function for style owned AJAX calls.
1451
   *
1452
   * Styles like the stylizer need AJAX callbacks of their own. This
1453
   * allows the system to figure out which style is being referenced,
1454
   * load it, and execute the callback.
1455
   *
1456
   * This allows those layouts to simply declare their callbacks and use
1457
   * them using $this->get_url('style', $command, $type, $pid).
1458
   */
1459
  function ajax_style() {
1460
    $args = func_get_args();
1461
    if (count($args) < 3) {
1462
      return MENU_NOT_FOUND;
1463
    }
1464

    
1465
    $command = array_shift($args);
1466
    $type = array_shift($args);
1467
    $pid = array_shift($args);
1468

    
1469
    $info = $this->get_style($type, $pid);
1470

    
1471
    $style = $info[0];
1472
    $conf = &$info[1];
1473

    
1474
    if (empty($style['ajax'][$command]) || !function_exists($style['ajax'][$command])) {
1475
      return MENU_NOT_FOUND;
1476
    }
1477

    
1478
    // Make sure the this is always available to the called functions.
1479
    $args = array_merge(array(&$this, $style, &$conf, $type, $pid), $args);
1480
    return call_user_func_array($style['ajax'][$command], $args);
1481
  }
1482

    
1483
  // ------------------------------------------------------------------------
1484
  // AJAX command generators
1485
  //
1486
  // These are used to make sure that child implementations can control their
1487
  // own AJAX commands as needed.
1488
  /**
1489
   * Create a command array to redraw a pane.
1490
   */
1491
  function command_update_pane($pid) {
1492
    if (is_object($pid)) {
1493
      $pane = $pid;
1494
    }
1495
    else {
1496
      $pane = $this->display->content[$pid];
1497
    }
1498

    
1499
    $this->commands[] = ajax_command_replace("#panel-pane-$pane->pid", $this->render_pane($pane));
1500
    $this->commands[] = ajax_command_changed("#panel-pane-$pane->pid", "div.grab-title span.text");
1501
  }
1502

    
1503
  /**
1504
   * Create a command array to add a new pane.
1505
   */
1506
  function command_add_pane($pid) {
1507
    if (is_object($pid)) {
1508
      $pane = $pid;
1509
    }
1510
    else {
1511
      $pane = $this->display->content[$pid];
1512
    }
1513

    
1514
    $this->commands[] = ajax_command_append("#panel-region-$pane->panel", $this->render_pane($pane));
1515
    $this->commands[] = ajax_command_changed("#panel-pane-$pane->pid", "div.grab-title span.text");
1516
  }
1517

    
1518
  /**
1519
   * Create a command to update the links on a display after a change was made.
1520
   */
1521
  function command_update_display_links() {
1522
    $this->commands[] = ajax_command_replace('.panels-display-links', $this->get_display_links());
1523
  }
1524

    
1525
  /**
1526
   * Create a command to update the links on a region after a change was made.
1527
   */
1528
  function command_update_region_links($id) {
1529
    $this->commands[] = ajax_command_replace('.panels-region-links-' . $id, $this->get_region_links($id));
1530
  }
1531

    
1532
}
1533

    
1534
/**
1535
 * Handle the 'next' click on the add/edit pane form wizard.
1536
 *
1537
 * All we need to do is store the updated pane in the cache.
1538
 */
1539
function panels_ajax_edit_pane_next(&$form_state) {
1540
  $form_state['display cache']->new_pane = $form_state['pane'];
1541
  panels_edit_cache_set($form_state['display cache']);
1542
}
1543

    
1544
/**
1545
 * Handle the 'finish' click on the add/edit pane form wizard.
1546
 *
1547
 * All we need to do is set a flag so the return can handle adding
1548
 * the pane.
1549
 */
1550
function panels_ajax_edit_pane_finish(&$form_state) {
1551
  $form_state['complete'] = TRUE;
1552
  return;
1553
}
1554

    
1555
/**
1556
 * Handle the 'cancel' click on the add/edit pane form wizard.
1557
 */
1558
function panels_ajax_edit_pane_cancel(&$form_state) {
1559
  $form_state['cancel'] = TRUE;
1560
  return;
1561
}
1562

    
1563
// --------------------------------------------------------------------------
1564
// Forms for the editor object.
1565
/**
1566
 * Choose cache method form.
1567
 */
1568
function panels_edit_cache_method_form($form, &$form_state) {
1569
  ctools_form_include($form_state, 'plugins', 'panels');
1570
  form_load_include($form_state, 'php', 'panels', '/plugins/display_renderers/panels_renderer_editor.class');
1571
  $display = &$form_state['display'];
1572
  $conf = &$form_state['conf'];
1573

    
1574
  // Set to 0 to ensure we get a selected radio.
1575
  if (!isset($conf['method'])) {
1576
    $conf['method'] = 0;
1577
  }
1578

    
1579
  $caches = panels_get_caches();
1580
  if (empty($caches)) {
1581
    $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.'));
1582
    return $form;
1583
  }
1584

    
1585
  $options[0] = t('No caching');
1586
  foreach ($caches as $cache => $info) {
1587
    $options[$cache] = check_plain($info['title']);
1588
  }
1589

    
1590
  $form['method'] = array(
1591
    '#prefix' => '<div class="no-float">',
1592
    '#suffix' => '</div>',
1593
    '#type' => 'radios',
1594
    '#title' => t('Method'),
1595
    '#options' => $options,
1596
    '#default_value' => $conf['method'],
1597
  );
1598

    
1599
  $form['submit'] = array(
1600
    '#type' => 'submit',
1601
    '#value' => t('Next'),
1602
  );
1603
  return $form;
1604
}
1605

    
1606
/**
1607
 * Submit callback for panels_edit_cache_method_form.
1608
 *
1609
 * All this needs to do is return the method.
1610
 */
1611
function panels_edit_cache_method_form_submit($form, &$form_state) {
1612
  $form_state['method'] = $form_state['values']['method'];
1613
}
1614

    
1615
/**
1616
 * Cache settings form.
1617
 */
1618
function panels_edit_cache_settings_form($form, &$form_state) {
1619
  ctools_form_include($form_state, 'plugins', 'panels');
1620
  form_load_include($form_state, 'php', 'panels', '/plugins/display_renderers/panels_renderer_editor.class');
1621
  $display = &$form_state['display'];
1622
  $conf = &$form_state['conf'];
1623
  $pid = $form_state['pid'];
1624
  $info = panels_get_cache($conf['method']);
1625

    
1626
  $form['#action'] = $form_state['url'];
1627

    
1628
  $form['description'] = array(
1629
    '#prefix' => '<div class="description">',
1630
    '#suffix' => '</div>',
1631
    '#value' => check_plain($info['description']),
1632
  );
1633

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

    
1636
  $form['settings'] = $function($conf['settings'], $display, $pid);
1637
  $form['settings']['#tree'] = TRUE;
1638

    
1639
  $form['display'] = array(
1640
    '#type' => 'value',
1641
    '#value' => $display,
1642
  );
1643

    
1644
  $form['pid'] = array(
1645
    '#type' => 'value',
1646
    '#value' => $pid,
1647
  );
1648

    
1649
  $form['submit'] = array(
1650
    '#type' => 'submit',
1651
    '#value' => t('Save'),
1652
  );
1653

    
1654
  return $form;
1655
}
1656

    
1657
/**
1658
 * Validate cache settings.
1659
 */
1660
function panels_edit_cache_settings_form_validate($form, &$form_state) {
1661
  if ($function = panels_plugin_get_function('cache', $form_state['conf']['method'], 'settings form validate')) {
1662
    $function($form, $form_state['values']['settings']);
1663
  }
1664
}
1665

    
1666
/**
1667
 * Allows panel styles to validate their style settings.
1668
 */
1669
function panels_edit_cache_settings_form_submit($form, &$form_state) {
1670
  if ($function = panels_plugin_get_function('cache', $form_state['conf']['method'], 'settings form submit')) {
1671
    $function($form_state['values']['settings']);
1672
  }
1673

    
1674
  $form_state['conf']['settings'] = $form_state['values']['settings'];
1675
}
1676

    
1677
/**
1678
 * Choose style form.
1679
 */
1680
function panels_edit_style_type_form($form, &$form_state) {
1681
  ctools_form_include($form_state, 'plugins', 'panels');
1682
  form_load_include($form_state, 'php', 'panels', '/plugins/display_renderers/panels_renderer_editor.class');
1683
  $display = &$form_state['display'];
1684
  $style = $form_state['style'];
1685
  $type = $form_state['type'];
1686

    
1687
  $styles = panels_get_styles();
1688

    
1689
  $function = ($type == 'pane' ? 'render pane' : 'render region');
1690
  $options = array();
1691
  if ($type == 'region') {
1692
    $options[-1] = t('Use display default style');
1693
  }
1694

    
1695
  uasort($styles, 'ctools_plugin_sort');
1696

    
1697
  foreach ($styles as $id => $info) {
1698
    if (empty($info['hidden']) && (!empty($info[$function]) || $id == 'default')) {
1699
      $options[$id] = check_plain($info['title']);
1700
    }
1701
  }
1702

    
1703
  $form['style'] = array(
1704
    '#prefix' => '<div class="no-float">',
1705
    '#suffix' => '</div>',
1706
    '#type' => 'radios',
1707
    '#title' => t('Style'),
1708
    '#options' => $options,
1709
    '#default_value' => $style,
1710
  );
1711

    
1712
  $form['submit'] = array(
1713
    '#type' => 'submit',
1714
    '#value' => t('Next'),
1715
  );
1716
  return $form;
1717
}
1718

    
1719
/**
1720
 * Submit callback for panels_edit_style_type_form.
1721
 *
1722
 * All this needs to do is return the method.
1723
 */
1724
function panels_edit_style_type_form_submit($form, &$form_state) {
1725
  $form_state['old_style'] = $form_state['style'];
1726
  $form_state['style'] = $form_state['values']['style'];
1727
}
1728

    
1729
/**
1730
 * Style settings form.
1731
 */
1732
function panels_edit_style_settings_form($form, &$form_state) {
1733
  ctools_form_include($form_state, 'plugins', 'panels');
1734
  form_load_include($form_state, 'php', 'panels', '/plugins/display_renderers/panels_renderer_editor.class');
1735
  $display = &$form_state['display'];
1736
  $conf = &$form_state['conf'];
1737
  $pid = $form_state['pid'];
1738
  $style = $form_state['style'];
1739
  $type = $form_state['type'];
1740

    
1741
  $form['#action'] = $form_state['url'];
1742

    
1743
  $form['description'] = array(
1744
    '#prefix' => '<div class="description">',
1745
    '#suffix' => '</div>',
1746
    '#value' => check_plain($style['description']),
1747
  );
1748

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

    
1751
  $form['settings'] = $function($conf, $display, $pid, $type, $form_state);
1752
  $form['settings']['#tree'] = TRUE;
1753

    
1754
  $form['submit'] = array(
1755
    '#type' => 'submit',
1756
    '#value' => t('Save'),
1757
  );
1758

    
1759
  // Need a cancel button since the style cache can persist and impact the wrong
1760
  // pane (or region, or display).
1761
  $form['cancel_style'] = array(
1762
    '#type' => 'submit',
1763
    '#value' => t('Cancel'),
1764
    '#submit' => array('panels_edit_style_settings_form_cancel'),
1765
  );
1766

    
1767
  return $form;
1768
}
1769

    
1770
/**
1771
 * Cancel style settings form.
1772
 *
1773
 * Clears the editing cache to prevent styles being applied to incorrect regions
1774
 * or panes.
1775
 */
1776
function panels_edit_style_settings_form_cancel($form, &$form_state) {
1777
  $form_state['cancel'] = TRUE;
1778
}
1779

    
1780
/**
1781
 * Validate style settings.
1782
 */
1783
function panels_edit_style_settings_form_validate($form, &$form_state) {
1784
  $name = $form_state['type'] == 'pane' ? 'pane settings form validate' : 'settings form validate';
1785
  if ($function = panels_plugin_get_function('styles', $form_state['style'], $name)) {
1786
    $function($form, $form_state['values']['settings'], $form_state);
1787
  }
1788
}
1789

    
1790
/**
1791
 * Allows panel styles to validate their style settings.
1792
 */
1793
function panels_edit_style_settings_form_submit($form, &$form_state) {
1794
  $name = $form_state['type'] == 'pane' ? 'pane settings form submit' : 'settings form submit';
1795
  if ($function = panels_plugin_get_function('styles', $form_state['style'], $name)) {
1796
    $function($form, $form_state['values']['settings'], $form_state);
1797
  }
1798

    
1799
  $form_state['conf'] = $form_state['values']['settings'];
1800
}
1801

    
1802

    
1803
/**
1804
 * Configure CSS on a pane form.
1805
 */
1806
function panels_edit_configure_pane_css_form($form, &$form_state) {
1807
  ctools_form_include($form_state, 'plugins', 'panels');
1808
  form_load_include($form_state, 'php', 'panels', '/plugins/display_renderers/panels_renderer_editor.class');
1809
  $display = &$form_state['display'];
1810
  $pane = &$form_state['pane'];
1811

    
1812
  $form['css_id'] = array(
1813
    '#type' => 'textfield',
1814
    '#default_value' => isset($pane->css['css_id']) ? $pane->css['css_id'] : '',
1815
    '#title' => t('CSS ID'),
1816
    '#description' => t('CSS ID to apply to this pane. This may be blank. Keywords from context are allowed.'),
1817
  );
1818
  $form['css_class'] = array(
1819
    '#type' => 'textfield',
1820
    '#default_value' => isset($pane->css['css_class']) ? $pane->css['css_class'] : '',
1821
    '#title' => t('CSS class'),
1822
    '#description' => t('CSS class to apply to this pane. This may be blank. Keywords from context are allowed.'),
1823
  );
1824

    
1825
  $form['next'] = array(
1826
    '#type' => 'submit',
1827
    '#value' => t('Save'),
1828
  );
1829

    
1830
  return $form;
1831
}
1832

    
1833
/**
1834
 * FAPI submission function for the CSS configure form.
1835
 *
1836
 * All this does is set up $pane properly. The caller is responsible for
1837
 * actually storing this somewhere.
1838
 */
1839
function panels_edit_configure_pane_css_form_submit($form, &$form_state) {
1840
  $pane = &$form_state['pane'];
1841
  $display = $form_state['display'];
1842

    
1843
  $pane->css['css_id'] = $form_state['values']['css_id'];
1844
  $pane->css['css_class'] = $form_state['values']['css_class'];
1845
}
1846

    
1847
/**
1848
 * Configure lock on a pane form.
1849
 */
1850
function panels_edit_configure_pane_lock_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
  if (empty($pane->locks)) {
1857
    $pane->locks = array('type' => 'none', 'regions' => array());
1858
  }
1859

    
1860
  $form['type'] = array(
1861
    '#type' => 'radios',
1862
    '#title' => t('Lock type'),
1863
    '#options' => array(
1864
      'none' => t('No lock'),
1865
      'immovable' => t('Immovable'),
1866
      'regions' => t('Regions'),
1867
    ),
1868
    '#default_value' => $pane->locks['type'],
1869
  );
1870

    
1871
  $layout = panels_get_layout($display->layout);
1872
  $regions = panels_get_regions($layout, $display);
1873

    
1874
  $form['regions'] = array(
1875
    '#type' => 'checkboxes',
1876
    '#title' => t('Regions'),
1877
    '#options' => $regions,
1878
    '#description' => t('Select which regions this pane can be moved to.'),
1879
    '#dependency' => array(
1880
      'radio:type' => array('regions'),
1881
    ),
1882
    '#default_value' => $pane->locks['regions'],
1883
  );
1884

    
1885
  $form['#after_build'][] = 'panels_edit_configure_pane_lock_form_after_build';
1886
  $form['next'] = array(
1887
    '#type' => 'submit',
1888
    '#value' => t('Save'),
1889
  );
1890

    
1891
  return $form;
1892
}
1893

    
1894
function panels_edit_configure_pane_lock_form_after_build($element, $form_state) {
1895
  $region = $form_state['pane']->panel;
1896
  $element['regions'][$region]['#required'] = TRUE;
1897
  $element['regions'][$region]['#disabled'] = TRUE;
1898
  $element['regions'][$region]['#value'] = TRUE;
1899
  $element['regions'][$region]['#checked'] = TRUE;
1900
  $element['regions'][$region]['#attributes']['disabled'] = TRUE;
1901
  return $element;
1902
}
1903

    
1904
/**
1905
 * FAPI submission function for the lock configure form.
1906
 *
1907
 * All this does is set up $pane properly. The caller is responsible for
1908
 * actually storing this somewhere.
1909
 */
1910
function panels_edit_configure_pane_lock_form_submit($form, &$form_state) {
1911
  $pane = &$form_state['pane'];
1912
  $display = $form_state['display'];
1913

    
1914
  // We set this to true but forms do not submit disabled checkboxes
1915
  // and fapi is ignoring the #value directive probably because it
1916
  // is checkboxes:
1917
  $region = $form_state['pane']->panel;
1918
  $form_state['values']['regions'][$region] = $region;
1919

    
1920
  $pane->locks['type'] = $form_state['values']['type'];
1921
  $pane->locks['regions'] = array_filter($form_state['values']['regions']);
1922
}
1923

    
1924
/**
1925
 * Form to control basic visibility settings.
1926
 */
1927
function panels_edit_configure_access_settings_form($form, &$form_state) {
1928
  ctools_form_include($form_state, 'plugins', 'panels');
1929
  form_load_include($form_state, 'php', 'panels', '/plugins/display_renderers/panels_renderer_editor.class');
1930
  $display = &$form_state['display'];
1931
  $pane = &$form_state['pane'];
1932

    
1933
  $form['logic'] = array(
1934
    '#type' => 'radios',
1935
    '#options' => array(
1936
      'and' => t('All criteria must pass.'),
1937
      'or' => t('Only one criterion must pass.'),
1938
    ),
1939
    '#default_value' => isset($pane->access['logic']) ? $pane->access['logic'] : 'and',
1940
  );
1941

    
1942
  $form['next'] = array(
1943
    '#type' => 'submit',
1944
    '#value' => t('Save'),
1945
  );
1946

    
1947
  return $form;
1948
}
1949

    
1950
/**
1951
 * FAPI submission function for the edit access settings form.
1952
 *
1953
 * All this does is set up $pane properly. The caller is responsible for
1954
 * actually storing this somewhere.
1955
 */
1956
function panels_edit_configure_access_settings_form_submit($form, &$form_state) {
1957
  $pane = &$form_state['pane'];
1958
  $display = $form_state['display'];
1959

    
1960
  $pane->access['logic'] = $form_state['values']['logic'];
1961
}
1962

    
1963
/**
1964
 * Form to add a visibility rule.
1965
 */
1966
function panels_edit_add_access_test_form($form, &$form_state) {
1967
  ctools_form_include($form_state, 'plugins', 'panels');
1968
  form_load_include($form_state, 'php', 'panels', '/plugins/display_renderers/panels_renderer_editor.class');
1969
  $display = &$form_state['display'];
1970
  $pane = &$form_state['pane'];
1971

    
1972
  $plugins = ctools_get_relevant_access_plugins($display->context);
1973
  $options = array();
1974
  foreach ($plugins as $id => $plugin) {
1975
    $options[$id] = $plugin['title'];
1976
  }
1977

    
1978
  asort($options);
1979

    
1980
  $form['type'] = array(
1981
    // This ensures that the form item is added to the URL.
1982
    '#type' => 'radios',
1983
    '#options' => $options,
1984
  );
1985

    
1986
  $form['next'] = array(
1987
    '#type' => 'submit',
1988
    '#value' => t('Next'),
1989
  );
1990

    
1991
  return $form;
1992
}
1993

    
1994
/**
1995
 * Form to configure a visibility rule.
1996
 */
1997
function panels_edit_configure_access_test_form($form, &$form_state) {
1998
  ctools_form_include($form_state, 'plugins', 'panels');
1999
  form_load_include($form_state, 'php', 'panels', '/plugins/display_renderers/panels_renderer_editor.class');
2000
  $display = &$form_state['display'];
2001
  $test = &$form_state['test'];
2002
  $plugin = &$form_state['plugin'];
2003

    
2004
  $form['#action'] = $form_state['url'];
2005

    
2006
  $contexts = $display->context;
2007
  if (!isset($contexts['logged-in-user'])) {
2008
    $contexts['logged-in-user'] = ctools_access_get_loggedin_context();
2009
  }
2010

    
2011
  if (isset($plugin['required context'])) {
2012
    $form['context'] = ctools_context_selector($contexts, $plugin['required context'], $test['context']);
2013
  }
2014

    
2015
  $form['settings'] = array('#tree' => TRUE);
2016
  if ($function = ctools_plugin_get_function($plugin, 'settings form')) {
2017
    $form = $function($form, $form_state, $test['settings']);
2018
  }
2019

    
2020
  $form['not'] = array(
2021
    '#type' => 'checkbox',
2022
    '#title' => t('Reverse (NOT)'),
2023
    '#default_value' => !empty($test['not']),
2024
  );
2025

    
2026
  $form['save'] = array(
2027
    '#type' => 'submit',
2028
    '#value' => t('Save'),
2029
  );
2030

    
2031
  $form['remove'] = array(
2032
    '#type' => 'submit',
2033
    '#value' => t('Remove'),
2034
    '#remove' => TRUE,
2035
  );
2036

    
2037
  return $form;
2038
}
2039

    
2040
/**
2041
 * Validate handler for visibility rule settings.
2042
 */
2043
function panels_edit_configure_access_test_form_validate(&$form, &$form_state) {
2044
  if (!empty($form_state['clicked_button']['#remove'])) {
2045
    return;
2046
  }
2047

    
2048
  if ($function = ctools_plugin_get_function($form_state['plugin'], 'settings form validate')) {
2049
    $function($form, $form_state);
2050
  }
2051
}
2052

    
2053
/**
2054
 * Submit handler for visibility rule settings.
2055
 */
2056
function panels_edit_configure_access_test_form_submit(&$form, &$form_state) {
2057
  if (!empty($form_state['clicked_button']['#remove'])) {
2058
    $form_state['remove'] = TRUE;
2059
    return;
2060
  }
2061

    
2062
  if ($function = ctools_plugin_get_function($form_state['plugin'], 'settings form submit')) {
2063
    $function($form, $form_state);
2064
  }
2065

    
2066
  $form_state['test']['settings'] = $form_state['values']['settings'];
2067
  if (isset($form_state['values']['context'])) {
2068
    $form_state['test']['context'] = $form_state['values']['context'];
2069
  }
2070
  $form_state['test']['not'] = !empty($form_state['values']['not']);
2071
}