Project

General

Profile

Paste
Download (64.8 KB) Statistics
| Branch: | Revision:

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

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
        $category = reset($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
            $pane->style['settings'] = NULL;
1056
          }
1057
          break;
1058
      }
1059
      panels_edit_cache_set($this->cache);
1060

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
1227
    panels_edit_cache_set($this->cache);
1228

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
1405
    $output = ctools_modal_form_wrapper('panels_edit_configure_access_test_form', $form_state);
1406
    $pane->access['plugins'][$id] = $form_state['test'];
1407

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
1533
}
1534

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
1655
  return $form;
1656
}
1657

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

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

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

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

    
1688
  $styles = panels_get_styles();
1689

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

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

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

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

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

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

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

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

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

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

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

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

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

    
1768
  return $form;
1769
}
1770

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

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

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

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

    
1803

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

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

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

    
1831
  return $form;
1832
}
1833

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

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

    
1848
/**
1849
 * Configure lock on a pane form.
1850
 */
1851
function panels_edit_configure_pane_lock_form($form, &$form_state) {
1852
  ctools_form_include($form_state, 'plugins', 'panels');
1853
  form_load_include($form_state, 'php', 'panels', '/plugins/display_renderers/panels_renderer_editor.class');
1854
  $display = &$form_state['display'];
1855
  $pane = &$form_state['pane'];
1856

    
1857
  if (empty($pane->locks)) {
1858
    $pane->locks = array('type' => 'none', 'regions' => array());
1859
  }
1860

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

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

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

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

    
1892
  return $form;
1893
}
1894

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

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

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

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

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

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

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

    
1948
  return $form;
1949
}
1950

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

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

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

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

    
1979
  asort($options);
1980

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

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

    
1992
  return $form;
1993
}
1994

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

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

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

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

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

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

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

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

    
2038
  return $form;
2039
}
2040

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

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

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

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

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