~spreadubuntu/spreadubuntu/devel-drupal6

« back to all changes in this revision

Viewing changes to sites/all/modules/views/includes/admin.inc

  • Committer: ruben
  • Date: 2009-06-08 09:38:49 UTC
  • Revision ID: ruben@captive-20090608093849-s1qtsyctv2vwp1x1
SpreadUbuntu moving to Drupal6. Based on ubuntu-drupal theme and adding our modules

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
<?php
 
2
// $Id: admin.inc,v 1.154 2009/04/07 20:48:28 merlinofchaos Exp $
 
3
/**
 
4
 * @file admin.inc
 
5
 * Provides the Views' administrative interface.
 
6
 */
 
7
 
 
8
/**
 
9
 * Page callback to list views in the system.
 
10
 */
 
11
function views_ui_list_views($arg = NULL) {
 
12
  if ($arg != NULL) {
 
13
    return drupal_not_found();
 
14
  }
 
15
 
 
16
  $output = theme('views_ui_list_views');
 
17
  views_ui_check_advanced_help();
 
18
  return $output;
 
19
}
 
20
 
 
21
/**
 
22
 * Check to see if the advanced help module is installed, and if not put up
 
23
 * a message.
 
24
 *
 
25
 * Only call this function if the user is already in a position for this to
 
26
 * be useful.
 
27
 */
 
28
function views_ui_check_advanced_help() {
 
29
  if (variable_get('views_hide_help_message', FALSE)) {
 
30
    return;
 
31
  }
 
32
 
 
33
  if (!module_exists('advanced_help')) {
 
34
    $filename = db_result(db_query("SELECT filename FROM {system} WHERE type = 'module' AND name = 'advanced_help'"));
 
35
    if ($filename && file_exists($filename)) {
 
36
      drupal_set_message(t('If you <a href="@modules">enable the advanced help module</a>, Views will provide more and better help. <a href="@hide">Hide this message.</a>', array('@modules' => url('admin/build/modules'),'@hide' => url('admin/build/views/tools'))));
 
37
    }
 
38
    else {
 
39
      drupal_set_message(t('If you install the advanced help module from !href, Views will provide more and better help. <a href="@hide">Hide this message.</a>', array('!href' => l('http://drupal.org/project/advanced_help', 'http://drupal.org/project/advanced_help'), '@hide' => url('admin/build/views/tools'))));
 
40
    }
 
41
  }
 
42
}
 
43
 
 
44
/**
 
45
 * Preprocess the list views theme
 
46
 */
 
47
function template_preprocess_views_ui_list_views(&$vars) {
 
48
  $items = array();
 
49
  $sorts = array();
 
50
 
 
51
  $views = views_get_all_views();
 
52
 
 
53
  // Respond to a reset command by clearing session and doing a drupal goto
 
54
  // back to the base URL.
 
55
  if (isset($_GET['op']) && $_GET['op'] == t('Reset')) {
 
56
    unset($_SESSION['views']['#admin']);
 
57
    drupal_goto('admin/build/views');
 
58
  }
 
59
  if (count($_GET) <= 1) {
 
60
    if (isset($_SESSION['views']['#admin']) && is_array($_SESSION['views']['#admin'])) {
 
61
      $_GET += $_SESSION['views']['#admin'];
 
62
    }
 
63
  }
 
64
  else {
 
65
    $_SESSION['views']['#admin'] = $_GET;
 
66
    unset($_SESSION['views']['#admin']['q']);
 
67
  }
 
68
 
 
69
  $form_state = array(
 
70
    'views' => $views,
 
71
    'input' => $_GET,
 
72
    'method' => 'get',
 
73
    'rerender' => TRUE,
 
74
    'no_redirect' => TRUE,
 
75
  );
 
76
 
 
77
  $vars['widgets'] = drupal_build_form('views_ui_list_views_form', $form_state);
 
78
 
 
79
  $vars['help_type_icon'] = theme('advanced_help_topic', 'views', 'view-type');
 
80
 
 
81
  $base_tables = views_fetch_base_tables();
 
82
 
 
83
  foreach ($views as $view) {
 
84
    if ($form_state['values']['tag'] != 'all') {
 
85
      if ($form_state['values']['tag'] == 'none') {
 
86
        if (!empty($view->tag)) {
 
87
          continue;
 
88
        }
 
89
      }
 
90
      else if ($form_state['values']['tag'] != $view->tag) {
 
91
        continue;
 
92
      }
 
93
    }
 
94
    if ($form_state['values']['type'] != 'all' && $form_state['values']['type'] != $view->type) {
 
95
      continue;
 
96
    }
 
97
 
 
98
    if ($form_state['values']['base'] != 'all' && $form_state['values']['base'] != $view->base_table) {
 
99
      continue;
 
100
    }
 
101
 
 
102
    if ($form_state['values']['display'] != 'all' && empty($view->display[$form_state['values']['display']])) {
 
103
      continue;
 
104
    }
 
105
 
 
106
    $item = new stdClass();
 
107
    $item->ops = array();
 
108
    if (empty($view->disabled)) {
 
109
      $item->ops[] = l(t('Edit'), "admin/build/views/edit/$view->name");
 
110
      $item->ops[] = l(t('Export'), "admin/build/views/export/$view->name");
 
111
      $item->ops[] = l(t('Clone'), "admin/build/views/clone/$view->name");
 
112
    }
 
113
    if ($view->type != t('Default')) {
 
114
      $text = $view->type == t('Overridden') ? t('Revert') : t('Delete');
 
115
      $item->ops[] = l($text, "admin/build/views/delete/$view->name");
 
116
    }
 
117
    else {
 
118
      if (empty($view->disabled)) {
 
119
        $item->ops[] = l(t('Disable'), "admin/build/views/disable/$view->name", array('query' => drupal_get_destination()));
 
120
      }
 
121
      else {
 
122
        $item->ops[] = l(t('Enable'), "admin/build/views/enable/$view->name", array('query' => drupal_get_destination()));
 
123
      }
 
124
    }
 
125
 
 
126
    $item->ops = implode(' | ', $item->ops);
 
127
    if (empty($view->display)) {
 
128
      $item->path = t('Warning! Broken view!');
 
129
    }
 
130
    else {
 
131
      $item->path = $raw_path = $view->get_path();
 
132
      $item->path = $item->path && empty($view->disabled) && strpos($item->path, '%') === FALSE ? l($item->path, $item->path) : check_plain($item->path);
 
133
    }
 
134
 
 
135
    $item->type = $view->type;
 
136
    $item->name = $view->name;
 
137
 
 
138
    if (!empty($view->tag)) {
 
139
      $item->tag = $view->tag;
 
140
    }
 
141
 
 
142
    $item->title = $view->get_title();
 
143
    $item->base = !empty($base_tables[$view->base_table]['title']) ? $base_tables[$view->base_table]['title'] : t('Broken');
 
144
 
 
145
    $item->displays = array();
 
146
    foreach ($view->display as $display) {
 
147
      if (!empty($display->handler->definition['admin'])) {
 
148
        $item->displays[$display->handler->definition['admin']] = TRUE;
 
149
      }
 
150
    }
 
151
 
 
152
    if ($item->displays) {
 
153
      ksort($item->displays);
 
154
      $item->displays = implode(', ', array_keys($item->displays));
 
155
    }
 
156
 
 
157
    $item->description = check_plain($view->description);
 
158
    $item->classes = empty($view->disabled) ? 'view-enabled' : 'view-disabled';
 
159
    $items[] = $item;
 
160
 
 
161
    $sort = intval(empty($view->disabled) xor $form_state['values']['sort'] == 'asc');
 
162
 
 
163
    switch ($form_state['values']['order']) {
 
164
      case 'name':
 
165
      default:
 
166
        $sort .= strtolower($view->name);
 
167
        break;
 
168
      case 'title':
 
169
        $sort .= strtolower($item->title);
 
170
        break;
 
171
      case 'path':
 
172
        $sort .= strtolower($raw_path); // $path;
 
173
        break;
 
174
      case 'type':
 
175
        $sort .= $view->type . $view->name;
 
176
        break;
 
177
      case 'tag':
 
178
        $sort .= strtolower($view->tag);
 
179
        break;
 
180
      case 'desc':
 
181
        $sort .= strtolower($view->description);
 
182
        break;
 
183
    }
 
184
 
 
185
    $sorts[] = $sort;
 
186
  }
 
187
 
 
188
  if ($form_state['values']['sort'] == 'desc') {
 
189
    arsort($sorts);
 
190
  }
 
191
  else {
 
192
    asort($sorts);
 
193
  }
 
194
 
 
195
  $i = array();
 
196
  foreach ($sorts as $id => $title) {
 
197
    $i[] = $items[$id];
 
198
  }
 
199
 
 
200
  views_add_css('views-list');
 
201
  $vars['views'] = $i;
 
202
 
 
203
  $getting_started = theme('advanced_help_topic', 'views', 'getting-started', 'title');
 
204
  if (!$getting_started) {
 
205
    $getting_started = t('Install the advanced help module for the getting started');
 
206
  }
 
207
 
 
208
  $vars['help'] = t('Not sure what to do? Try the "!getting-started" page.', array('!getting-started' => $getting_started));
 
209
}
 
210
 
 
211
/**
 
212
 * Provide a form for sorting and filtering the list of views.
 
213
 */
 
214
function views_ui_list_views_form(&$form_state) {
 
215
  if (!variable_get('clean_url', FALSE)) {
 
216
    $form['q'] = array(
 
217
      '#type' => 'hidden',
 
218
      '#value' => $_GET['q'],
 
219
    );
 
220
  }
 
221
 
 
222
  $all = array('all' => t('<All>'));
 
223
  $none = array('none' => t('<None>'));
 
224
 
 
225
  $form['type'] = array(
 
226
    '#type' => 'select',
 
227
    '#title' => t('Storage'),
 
228
    '#options' => array(
 
229
      'all' => t('<All>'),
 
230
      t('Normal') => t('Normal'),
 
231
      t('Default') => t('Default'),
 
232
      t('Overridden') => t('Overridden'),
 
233
    ),
 
234
    '#default_value' => 'all',
 
235
  );
 
236
 
 
237
  $bases = array();
 
238
  foreach (views_fetch_base_tables() as $table => $info) {
 
239
    $bases[$table] = $info['title'];
 
240
  }
 
241
 
 
242
  $form['base'] = array(
 
243
    '#type' => 'select',
 
244
    '#title' => t('Type'),
 
245
    '#options' => array_merge($all, $bases),
 
246
    '#default_value' => 'all',
 
247
  );
 
248
 
 
249
  $tags = array();
 
250
 
 
251
  $extras = array();
 
252
  foreach ($form_state['views'] as $name => $view) {
 
253
    if (!empty($view->tag)) {
 
254
      $tags[$view->tag] = $view->tag;
 
255
    }
 
256
  }
 
257
 
 
258
  asort($tags);
 
259
 
 
260
  $form['tag'] = array(
 
261
    '#type' => 'select',
 
262
    '#title' => t('Tag'),
 
263
    '#options' => array_merge($all, $none, $tags),
 
264
    '#default_value' => 'all',
 
265
  );
 
266
 
 
267
  $displays = array();
 
268
  foreach (views_fetch_plugin_data('display') as $id => $info) {
 
269
    if (!empty($info['admin'])) {
 
270
      $displays[$id] = $info['admin'];
 
271
    }
 
272
  }
 
273
 
 
274
  asort($displays);
 
275
 
 
276
  $form['display'] = array(
 
277
    '#type' => 'select',
 
278
    '#title' => t('Displays'),
 
279
    '#options' => array_merge($all, $displays),
 
280
    '#default_value' => 'all',
 
281
  );
 
282
 
 
283
  $form['order'] = array(
 
284
    '#type' => 'select',
 
285
    '#title' => t('Sort by'),
 
286
    '#options' => array(
 
287
      'name' => t('Name'),
 
288
      'title' => t('Title'),
 
289
      'tag' => t('Tag'),
 
290
      'path' => t('Path'),
 
291
      'type' => t('Type'),
 
292
      'desc' => t('Description'),
 
293
    ),
 
294
    '#default_value' => 'name',
 
295
  );
 
296
 
 
297
  $form['sort'] = array(
 
298
    '#type' => 'select',
 
299
    '#title' => t('Order'),
 
300
    '#options' => array(
 
301
      'asc' => t('Up'),
 
302
      'desc' => t('Down'),
 
303
    ),
 
304
    '#default_value' => 'asc',
 
305
  );
 
306
 
 
307
  $form['submit'] = array(
 
308
    '#name' => '', // so it won't in the $_GET args
 
309
    '#type' => 'submit',
 
310
    '#id' => 'edit-views-apply',
 
311
    '#value' => t('Apply'),
 
312
  );
 
313
 
 
314
  if (!empty($_SESSION['views']['#admin'])) {
 
315
    $form['reset'] = array(
 
316
      '#type' => 'submit',
 
317
      '#id' => 'edit-views-reset',
 
318
      '#value' => t('Reset'),
 
319
    );
 
320
  }
 
321
 
 
322
  $form['#theme'] = array('views_ui_list_views_form');
 
323
  return $form;
 
324
}
 
325
 
 
326
function theme_views_ui_list_views_form($form) {
 
327
  // Don't render these:
 
328
  unset($form['form_id']);
 
329
  unset($form['form_build_id']);
 
330
  unset($form['form_token']);
 
331
  return drupal_render($form);
 
332
}
 
333
 
 
334
/**
 
335
 * Page callback for the live preview.
 
336
 *
 
337
 * @todo make this use a template
 
338
 */
 
339
function views_ui_preview($js, $view) {
 
340
  // Take off the items we know so that we can have just the args passed
 
341
  // in for later use.
 
342
  $func_args = func_get_args();
 
343
  array_shift($func_args); // $js
 
344
  array_shift($func_args); // $view
 
345
  $display_id = (count($func_args)) ? array_shift($func_args) : 'default';
 
346
 
 
347
  $form_state = array(
 
348
    'display_id' => $display_id,
 
349
    'view_args' => $func_args ? implode('/', $func_args) : '',
 
350
    'rerender' => TRUE,
 
351
    'no_redirect' => TRUE,
 
352
    'view' => &$view,
 
353
    'ajax' => $js
 
354
  );
 
355
 
 
356
  $output = drupal_build_form('views_ui_preview_form', $form_state);
 
357
  $args = array();
 
358
  if (isset($form_state['view_args']) && $form_state['view_args'] !== '') {
 
359
    $args = explode('/', $form_state['view_args']);
 
360
  }
 
361
 
 
362
  $errors = $view->validate();
 
363
  if ($errors === TRUE) {
 
364
    $view->ajax = $js;
 
365
    $view->live_preview = TRUE;
 
366
 
 
367
    // Store the current view URL for later use:
 
368
    $view->set_display($form_state['display_id']);
 
369
    $view->set_arguments($args);
 
370
 
 
371
    if ($view->display_handler->get_option('path')) {
 
372
      $path = $view->get_url();
 
373
    }
 
374
 
 
375
    // Make view links come back to preview.
 
376
    $view->override_path = 'admin/build/views/nojs/preview/' . $view->name . '/' . $form_state['display_id'];
 
377
 
 
378
    // also override $_GET['q'] so we get the pager
 
379
    $_GET['q'] = $view->override_path;
 
380
    if ($form_state['view_args']) {
 
381
      $_GET['q'] .= '/' . $form_state['view_args'];
 
382
    }
 
383
 
 
384
    $preview = $view->preview($form_state['display_id'], $args);
 
385
 
 
386
    // Get information from the preview for display.
 
387
    if (!empty($view->build_info['query'])) {
 
388
      $rows = array();
 
389
      $query = db_prefix_tables($view->build_info['query']);
 
390
      if ($view->build_info['query_args']) {
 
391
        _db_query_callback($view->build_info['query_args'], TRUE);
 
392
        $query = preg_replace_callback(DB_QUERY_REGEXP, '_db_query_callback', $query);
 
393
      }
 
394
      $rows[] = array('<strong>' . t('Query') . '</strong>', '<pre>' . check_plain($query) . '</pre>');
 
395
      if (!empty($view->additional_queries)) {
 
396
        $queries = '<strong>' . t('These queries were run during view rendering:') . '</strong>';
 
397
        foreach ($view->additional_queries as $query) {
 
398
          if ($queries) {
 
399
            $queries .= "\n";
 
400
          }
 
401
          $queries .= t('[@time ms]', array('@time' => intval($query[1] * 100000) / 100)) . ' ' . $query[0];
 
402
        }
 
403
 
 
404
        $rows[] = array('<strong>' . t('Other queries') . '</strong>', '<pre>' . $queries . '</pre>');
 
405
      }
 
406
 
 
407
      $rows[] = array('<strong>' . t('Title') . '</strong>', filter_xss_admin($view->get_title()));
 
408
      if (isset($path)) {
 
409
        $path = l($path, $path);
 
410
      }
 
411
      else {
 
412
        $path = t('This display has no path.');
 
413
      }
 
414
 
 
415
      $rows[] = array('<strong>' . t('Path') . '</strong>', $path);
 
416
 
 
417
      $rows[] = array('<strong>' . t('Query build time') . '</strong>', t('@time ms', array('@time' => intval($view->build_time * 100000) / 100)));
 
418
      $rows[] = array('<strong>' . t('Query execute time') . '</strong>', t('@time ms', array('@time' => intval($view->execute_time * 100000) / 100)));
 
419
      $rows[] = array('<strong>' . t('View render time') . '</strong>', t('@time ms', array('@time' => intval($view->render_time * 100000) / 100)));
 
420
      drupal_alter('views_preview_info', $rows, $view);
 
421
 
 
422
      $info = theme('table', array(), $rows);
 
423
    }
 
424
    else {
 
425
      $info = theme('table', array(), array(array('<strong>' . t('Query') . '</strong>', t('No query was run'))));
 
426
    }
 
427
  }
 
428
  else {
 
429
    foreach ($errors as $error) {
 
430
      drupal_set_message($error, 'error');
 
431
    }
 
432
    $preview = t('Unable to preview due to validation errors.');
 
433
    $info = '';
 
434
  }
 
435
 
 
436
  $info = '<div class="views-query-info">' . $info . '</div>';
 
437
 
 
438
  if (variable_get('views_ui_query_on_top', FALSE)) {
 
439
    $output .= $info . $preview;
 
440
  }
 
441
  else {
 
442
    $output .= $preview . $info;
 
443
  }
 
444
 
 
445
  if (!$js) {
 
446
    views_add_css('views-admin');
 
447
    drupal_set_title($view->get_title());
 
448
    return $output;
 
449
  }
 
450
  else {
 
451
    views_include('ajax');
 
452
    $object = new stdClass();
 
453
    if (!empty($view->js_settings)) {
 
454
      $object->js = $view->js_settings;
 
455
    }
 
456
    $object->display = '';
 
457
    if ($messages = theme('status_messages')) {
 
458
      $object->display = '<div class="views-messages">' . $messages . '</div>';
 
459
    }
 
460
    $object->display .= $output;
 
461
    $object->title = $view->get_title();
 
462
    views_ajax_render($object);
 
463
  }
 
464
}
 
465
 
 
466
/**
 
467
 * Form for generating argument information for the live preview.
 
468
 */
 
469
function views_ui_preview_form(&$form_state) {
 
470
  $view = &$form_state['view'];
 
471
  $view->init_display();
 
472
  $options = array();
 
473
  foreach ($view->display as $id => $display) {
 
474
    $options[$id] = $display->display_title;
 
475
  }
 
476
 
 
477
  $form['#attributes'] = array(
 
478
    'class' => 'clear-block',
 
479
  );
 
480
 
 
481
  $form['display_id'] = array(
 
482
    '#type' => 'select',
 
483
    '#title' => t('Display'),
 
484
    '#options' => $options,
 
485
    '#default_value' => $form_state['display_id'],
 
486
    '#id' => 'preview-display-id',
 
487
  );
 
488
 
 
489
  $form['args'] = array(
 
490
    '#type' => 'textfield',
 
491
    '#title' => t('Arguments'),
 
492
    '#default_value' => $form_state['view_args'],
 
493
    '#description' => t('Separate arguments with a / as though they were a URL path.'),
 
494
    '#id' => 'preview-args',
 
495
  );
 
496
 
 
497
  $form['preview'] = array(
 
498
    '#type' => 'submit',
 
499
    '#value' => t('Preview'),
 
500
    '#id' => 'preview-submit',
 
501
  );
 
502
 
 
503
  $form['#action'] = url("admin/build/views/nojs/preview/$view->name");
 
504
  return $form;
 
505
}
 
506
 
 
507
/**
 
508
 * Submit the preview form.
 
509
 *
 
510
 * This just takes the data and stores it on the form state in a
 
511
 * known location. The caller will be responsible for using it.
 
512
 */
 
513
function views_ui_preview_form_submit(&$form, &$form_state) {
 
514
  $form_state['display_id'] = $form_state['values']['display_id'];
 
515
  $form_state['view_args'] = $form_state['values']['args'];
 
516
}
 
517
 
 
518
/**
 
519
 * Page callback to add a new view.
 
520
 */
 
521
function views_ui_add_page() {
 
522
  $form_state = array(
 
523
    'view' => NULL
 
524
  );
 
525
 
 
526
  return drupal_build_form('views_ui_add_form', $form_state);
 
527
}
 
528
 
 
529
/**
 
530
 * Page callback to add a new view.
 
531
 */
 
532
function views_ui_clone_page($view) {
 
533
  $form_state = array(
 
534
    'view' => $view->copy(),
 
535
  );
 
536
 
 
537
  drupal_set_title(t('Clone view %view', array('%view' => $view->name)));
 
538
  return drupal_build_form('views_ui_add_form', $form_state);
 
539
}
 
540
 
 
541
/**
 
542
 * Form constructor callback to create the views Add Form, phase 1.
 
543
 */
 
544
function views_ui_add_form(&$form_state) {
 
545
  $view = $form_state['view'];
 
546
  $form = array();
 
547
 
 
548
  $form['name'] = array(
 
549
    '#type' => 'textfield',
 
550
    '#title' => t('View name'),
 
551
    '#description' => t('This is the unique name of the view. It must contain only alphanumeric characters and underscores; it is used to identify the view internally and to generate unique theming template names for this view. If overriding a module provided view, the name must not be changed or instead a new view will be created.'),
 
552
    '#required' => TRUE,
 
553
    '#maxlength' => 32,
 
554
    '#default_value' => $view ? $view->name : '',
 
555
    '#attributes' => array('dir'=>'ltr'),
 
556
  );
 
557
 
 
558
  $form['description'] = array(
 
559
    '#type' => 'textfield',
 
560
    '#title' => t('View description'),
 
561
    '#description' => t('This description will appear on the Views administrative UI to tell you what the view is about.'),
 
562
    '#default_value' => $view ? $view->description : '',
 
563
  );
 
564
 
 
565
  $form['tag'] = array(
 
566
    '#type' => 'textfield',
 
567
    '#title' => t('View tag'),
 
568
    '#description' => t('Enter an optional tag for this view; it is used only to help sort views on the administrative page.'),
 
569
    '#default_value' => $view ? $view->tag : '',
 
570
    '#autocomplete_path' => 'admin/views/ajax/autocomplete/tag',
 
571
  );
 
572
 
 
573
  $base_tables = array();
 
574
  foreach (views_fetch_base_tables() as $table => $info) {
 
575
    $base_tables[$table] = $info['title'] . '<div class="description">' . $info['description'] . '</div>';
 
576
  }
 
577
 
 
578
  $form['base_table'] = array(
 
579
    '#type' => 'radios',
 
580
    '#title' => t('View type'),
 
581
    '#description' => t('The view type is the primary table for which information is being retrieved. The view type controls what arguments, fields, sort criteria and filters are available, so once this is set it <strong>cannot be changed</strong>.'),
 
582
    '#default_value' => $view ? $view->base_table : 'node',
 
583
    '#options' => $base_tables,
 
584
  );
 
585
 
 
586
  if ($view) {
 
587
    $form['base_table']['#disabled'] = TRUE;
 
588
  }
 
589
 
 
590
  $form['submit'] = array(
 
591
    '#type' => 'submit',
 
592
    '#value' => t('Next'),
 
593
    '#validate' => array('views_ui_add_form_validate'),
 
594
    '#submit' => array('views_ui_add_form_submit'),
 
595
  );
 
596
 
 
597
  return $form;
 
598
}
 
599
 
 
600
/**
 
601
 * Validate the add view form.
 
602
 */
 
603
function views_ui_add_form_validate($form, &$form_state) {
 
604
  $name = $form_state['values']['name'];
 
605
 
 
606
  // View name must be alphanumeric or underscores, no other punctuation.
 
607
  if (preg_match('/[^a-zA-Z0-9_]/', $name)) {
 
608
    form_error($form['name'], t('View name must be alphanumeric or underscores only.'));
 
609
  }
 
610
 
 
611
  // View name must already exist.
 
612
  $view = views_get_view($form_state['values']['name']);
 
613
  if ($view && $view->type != t('Default')) {
 
614
    form_error($form['name'], t('You must use a unique name for this view.'));
 
615
  }
 
616
}
 
617
 
 
618
/**
 
619
 * Process the add view form
 
620
 */
 
621
function views_ui_add_form_submit($form, &$form_state) {
 
622
  $view = $form_state['view'] ? $form_state['view'] : views_new_view();
 
623
  $view->name = $form_state['values']['name'];
 
624
  $view->description = $form_state['values']['description'];
 
625
  $view->tag = $form_state['values']['tag'];
 
626
  if (empty($form['base_table']['#disabled'])) {
 
627
    $view->base_table = $form_state['values']['base_table'];
 
628
  }
 
629
 
 
630
  views_ui_cache_set($view);
 
631
  $form_state['redirect'] ='admin/build/views/edit/' . $view->name;
 
632
}
 
633
 
 
634
/**
 
635
 * Page to delete a view.
 
636
 */
 
637
function views_ui_delete_confirm(&$form_state, $view) {
 
638
  $form_state['view'] = &$view;
 
639
  $form = array();
 
640
 
 
641
  $cancel = 'admin/build/views';
 
642
  if (!empty($_REQUEST['cancel'])) {
 
643
    $cancel = $_REQUEST['cancel'];
 
644
  }
 
645
 
 
646
  if ($view->type == t('Overridden')) {
 
647
    $title = t('Are you sure you want to revert the view %name?', array('%name' => $view->name));
 
648
    $desc = t('Reverting the view will delete the view that is in the database, reverting it to the original default view. Any changes you have made will be lost and cannot be recovered.');
 
649
    $button = t('Revert');
 
650
  }
 
651
  else {
 
652
    $title = t('Are you sure you want to delete the view %name?', array('%name' => $view->name));
 
653
    $desc = t('Deleting a view cannot be undone.');
 
654
    $button = t('Delete');
 
655
  }
 
656
 
 
657
  return confirm_form($form,
 
658
                  $title,
 
659
                  $cancel,
 
660
                  $desc,
 
661
                  $button,
 
662
                  t('Cancel'));
 
663
}
 
664
 
 
665
/**
 
666
 * Submit handler to delete a view.
 
667
 */
 
668
function views_ui_delete_confirm_submit(&$form, &$form_state) {
 
669
  $form_state['view']->delete();
 
670
  views_object_cache_clear('view', $form_state['view']->name);
 
671
  drupal_set_message(t('The view has been deleted.'));
 
672
  $form_state['redirect'] = 'admin/build/views';
 
673
}
 
674
 
 
675
/**
 
676
 * Page to delete a view.
 
677
 */
 
678
function views_ui_break_lock_confirm(&$form_state, $view) {
 
679
  $form_state['view'] = &$view;
 
680
  $form = array();
 
681
 
 
682
  if (empty($view->locked)) {
 
683
    return t('There is no lock on view %view to break.', array('%name' => $view->name));
 
684
  }
 
685
 
 
686
  $cancel = 'admin/build/views/edit/' . $view->name;
 
687
  if (!empty($_REQUEST['cancel'])) {
 
688
    $cancel = $_REQUEST['cancel'];
 
689
  }
 
690
 
 
691
  $account = user_load($view->locked->uid);
 
692
  return confirm_form($form,
 
693
                  t('Are you sure you want to break the lock on view %name?',
 
694
                  array('%name' => $view->name)),
 
695
                  $cancel,
 
696
                  t('By breaking this lock, any unsaved changes made by !user will be lost!', array('!user' => theme('username', $account))),
 
697
                  t('Break lock'),
 
698
                  t('Cancel'));
 
699
}
 
700
 
 
701
/**
 
702
 * Submit handler to break_lock a view.
 
703
 */
 
704
function views_ui_break_lock_confirm_submit(&$form, &$form_state) {
 
705
  db_query("DELETE FROM {views_object_cache} WHERE obj = 'view' AND name = '%s'", $form_state['view']->name);
 
706
  $form_state['redirect'] = 'admin/build/views/edit/' . $form_state['view']->name;
 
707
  drupal_set_message(t('The lock has been broken and you may now edit this view.'));
 
708
}
 
709
 
 
710
/**
 
711
 * The main view edit page
 
712
 */
 
713
function views_ui_edit_page($view) {
 
714
  drupal_set_title(t('Edit view %view', array('%view' => $view->name)));
 
715
  $output = theme('views_ui_edit_view', $view);
 
716
  views_ui_check_advanced_help();
 
717
  return $output;
 
718
}
 
719
 
 
720
/**
 
721
 * Export a view for cut & paste.
 
722
 */
 
723
function views_ui_export_page(&$form_state, $view) {
 
724
  $code = $view->export();
 
725
  $lines = substr_count($code, "\n");
 
726
  $form['code'] = array(
 
727
    '#type' => 'textarea',
 
728
    '#title' => $view->name,
 
729
    '#default_value' => $code,
 
730
    '#rows' => $lines,
 
731
  );
 
732
  return $form;
 
733
}
 
734
 
 
735
/**
 
736
 * Import a view from cut & paste
 
737
 */
 
738
function views_ui_import_page(&$form_state) {
 
739
  $form['name'] = array(
 
740
    '#type' => 'textfield',
 
741
    '#title' => t('View name'),
 
742
    '#description' => t('Enter the name to use for this view if it is different from the source view. Leave blank to use the name of the view.'),
 
743
  );
 
744
 
 
745
  $form['view'] = array(
 
746
    '#type' => 'textarea',
 
747
    '#title' => t('Paste view code here'),
 
748
  );
 
749
 
 
750
  $form['submit'] = array(
 
751
    '#type' => 'submit',
 
752
    '#value' => t('Import'),
 
753
    '#submit' => array('views_ui_import_submit'),
 
754
    '#validate' => array('views_ui_import_validate'),
 
755
  );
 
756
  return $form;
 
757
}
 
758
 
 
759
/**
 
760
 * Validate handler to import a view
 
761
 */
 
762
function views_ui_import_validate($form, &$form_state) {
 
763
  views_include('view');
 
764
  ob_start();
 
765
  eval($form_state['values']['view']);
 
766
  ob_end_clean();
 
767
 
 
768
  if (!is_object($view)) {
 
769
    form_error($form['view'], t('Unable to interpret view code.'));
 
770
  }
 
771
 
 
772
  if (empty($view->api_version) || $view->api_version < 2) {
 
773
    // Check for some value that would only exist on a Views 1 view.
 
774
    if (isset($view->url) || isset($view->page) || isset($view->block)) {
 
775
      views_include('convert');
 
776
      $view = views1_import($view);
 
777
      drupal_set_message(t('You are importing a view created in Views version 1. You may need to adjust some parameters to work correctly in version 2.'), 'warning');
 
778
    }
 
779
    else {
 
780
      form_error($form['view'], t('That view is not compatible with this version of Views.'));
 
781
    }
 
782
  }
 
783
 
 
784
  // View name must be alphanumeric or underscores, no other punctuation.
 
785
  if (!empty($form_state['values']['name']) && preg_match('/[^a-zA-Z0-9_]/', $form_state['values']['name'])) {
 
786
    form_error($form['name'], t('View name must be alphanumeric or underscores only.'));
 
787
  }
 
788
 
 
789
  if ($form_state['values']['name']) {
 
790
    $view->name = $form_state['values']['name'];
 
791
  }
 
792
 
 
793
  $test = views_get_view($view->name);
 
794
  if ($test && $test->type != t('Default')) {
 
795
    form_set_error('', t('A view by that name already exists; please choose a different name'));
 
796
  }
 
797
 
 
798
  $view->init_display();
 
799
 
 
800
  $broken = FALSE;
 
801
  // Make sure that all plugins and handlers needed by this view actually exist.
 
802
  foreach ($view->display as $id => $display) {
 
803
    if (empty($display->handler) || !empty($display->handler->broken)) {
 
804
      drupal_set_message(t('Display plugin @plugin is not available.', array('@plugin' => $display->display_plugin)), 'error');
 
805
      $broken = TRUE;
 
806
      continue;
 
807
    }
 
808
 
 
809
    $plugin = views_get_plugin('style', $display->handler->get_option('style_plugin'));
 
810
    if (!$plugin) {
 
811
      drupal_set_message(t('Style plugin @plugin is not available.', array('@plugin' => $display->handler->get_option('style_plugin'))), 'error');
 
812
      $broken = TRUE;
 
813
    }
 
814
    else if ($plugin->uses_row_plugin()) {
 
815
      $plugin = views_get_plugin('row', $display->handler->get_option('row_plugin'));
 
816
      if (!$plugin) {
 
817
        drupal_set_message(t('Row plugin @plugin is not available.', array('@plugin' => $display->handler->get_option('row_plugin'))), 'error');
 
818
        $broken = TRUE;
 
819
      }
 
820
    }
 
821
 
 
822
    foreach (views_object_types() as $type => $info) {
 
823
      $handlers = $display->handler->get_handlers($type);
 
824
      if ($handlers) {
 
825
        foreach ($handlers as $id => $handler) {
 
826
          if ($handler->broken()) {
 
827
            drupal_set_message(t('@type handler @table.@field is not available.', array(
 
828
              '@type' => $info['stitle'],
 
829
              '@table' => $handler->table,
 
830
              '@field' => $handler->field,
 
831
            )), 'error');
 
832
            $broken = TRUE;
 
833
          }
 
834
        }
 
835
      }
 
836
    }
 
837
  }
 
838
 
 
839
  if ($broken) {
 
840
    form_set_error('', t('Unable to import view.'));
 
841
  }
 
842
 
 
843
  $form_state['view'] = &$view;
 
844
}
 
845
 
 
846
/**
 
847
 * Submit handler for view import
 
848
 */
 
849
function views_ui_import_submit($form, &$form_state) {
 
850
  // Store in cache and then go to edit.
 
851
  views_ui_cache_set($form_state['view']);
 
852
  $form_state['redirect'] = 'admin/build/views/edit/' . $form_state['view']->name;
 
853
}
 
854
 
 
855
/**
 
856
 * The main edit view form, which is really just a save/cancel/delete button.
 
857
 */
 
858
function views_ui_edit_view_form(&$form_state, $view) {
 
859
  $form['buttons']['save'] = array(
 
860
    '#type' => 'submit',
 
861
    '#value' => t('Save'),
 
862
    '#validate' => array('views_ui_edit_view_form_validate'),
 
863
    '#submit' => array('views_ui_edit_view_form_submit'),
 
864
  );
 
865
 
 
866
  $form['buttons']['cancel'] = array(
 
867
    '#type' => 'submit',
 
868
    '#value' => t('Cancel'),
 
869
    '#submit' => array('views_ui_edit_view_form_cancel'),
 
870
  );
 
871
 
 
872
  if (is_numeric($view->vid)) {
 
873
    $form['buttons']['delete'] = array(
 
874
      '#type' => 'submit',
 
875
      '#value' => t('Delete'),
 
876
      '#submit' => array('views_ui_edit_view_form_delete'),
 
877
    );
 
878
  }
 
879
 
 
880
  $form_state['view'] = &$view;
 
881
  return $form;
 
882
}
 
883
 
 
884
/**
 
885
 * Validate that a view is complete and whole.
 
886
 */
 
887
function views_ui_edit_view_form_validate($form, &$form_state) {
 
888
  // Do not validate cancel or delete.
 
889
  if (empty($form_state['clicked_button']['#value']) || $form_state['clicked_button']['#value'] != t('Save')) {
 
890
    return;
 
891
  }
 
892
 
 
893
  $errors = $form_state['view']->validate();
 
894
  if ($errors !== TRUE) {
 
895
    foreach ($errors as $error) {
 
896
      form_set_error('', $error);
 
897
    }
 
898
  }
 
899
}
 
900
 
 
901
/**
 
902
 * Submit handler for the edit view form.
 
903
 */
 
904
function views_ui_edit_view_form_submit($form, &$form_state) {
 
905
  // Go through and remove displayed scheduled for removal.
 
906
  foreach ($form_state['view']->display as $id => $display) {
 
907
    if (!empty($display->deleted)) {
 
908
      unset($form_state['view']->display[$id]);
 
909
    }
 
910
  }
 
911
 
 
912
  $form_state['view']->save();
 
913
  drupal_set_message(t('The view has been saved.'));
 
914
 
 
915
  // Make sure menu items get rebuilt as neces
 
916
  menu_rebuild();
 
917
 
 
918
  // Clear the views cache.
 
919
  cache_clear_all('*', 'cache_views');
 
920
 
 
921
  // Clear the page cache.
 
922
  cache_clear_all();
 
923
 
 
924
  // Remove this view from cache so we can edit it properly.
 
925
  views_object_cache_clear('view', $form_state['view']->name);
 
926
}
 
927
 
 
928
/**
 
929
 * Submit handler for the edit view form.
 
930
 */
 
931
function views_ui_edit_view_form_cancel($form, &$form_state) {
 
932
  // Remove this view from cache so edits will be lost.
 
933
  views_object_cache_clear('view', $form_state['view']->name);
 
934
  if (empty($form['view']->vid)) {
 
935
    // I seem to have to drupal_goto here because I can't get fapi to
 
936
    // honor the redirect target. Not sure what I screwed up here.
 
937
    drupal_goto('admin/build/views');
 
938
  }
 
939
}
 
940
 
 
941
function views_ui_edit_view_form_delete($form, &$form_state) {
 
942
  unset($_REQUEST['destination']);
 
943
  // Redirect to the delete confirm page
 
944
  $form_state['redirect'] = array('admin/build/views/delete/' . $form_state['view']->name, 'cancel=admin/build/views/edit/' . $form_state['view']->name);
 
945
}
 
946
 
 
947
/**
 
948
 * Preprocess the view edit page.
 
949
 */
 
950
function template_preprocess_views_ui_edit_view(&$vars) {
 
951
  $view = &$vars['view'];
 
952
 
 
953
  $vars['save_button'] = drupal_get_form('views_ui_edit_view_form', $view);
 
954
 
 
955
  $table = views_fetch_data($view->base_table);
 
956
  $vars['base_table'] = !empty($table['table']['base']['title']) ?
 
957
    $table['table']['base']['title'] : t('Unknown or missing table name');
 
958
 
 
959
  views_include('tabs');
 
960
  $tabs = new views_tabset;
 
961
 
 
962
  $vars['message'] = '<div class="message">' . t("Click on an item to edit that item's details.") . '</div>';
 
963
 
 
964
  if (!$view->set_display('default')) {
 
965
    drupal_set_message(t('This view has a broken default display and cannot be used.'), 'error');
 
966
  }
 
967
 
 
968
  foreach ($view->display as $display) {
 
969
    list($title, $body) = views_ui_display_tab($view, $display);
 
970
    // The first display is the default.
 
971
    $tabs->set($display->id, $title, $body);
 
972
  }
 
973
 
 
974
  // This is the area that will render beneath the links
 
975
  $form_state = array(
 
976
    'view' => &$view,
 
977
    'ajax' => FALSE,
 
978
  );
 
979
 
 
980
  $display_button = drupal_build_form('views_ui_add_display_form', $form_state);
 
981
  $analyze_button = drupal_get_form('views_ui_analyze_view_button', $view);
 
982
  $tabs->add_extra($display_button . $analyze_button);
 
983
 
 
984
  $vars['tabs'] = $tabs->render();
 
985
 
 
986
  $form_state = array(
 
987
    'display_id' => 'default',
 
988
    'view_args' => '',
 
989
    'rerender' => FALSE,
 
990
    'no_redirect' => TRUE,
 
991
    'view' => &$view,
 
992
    'input' => array(),
 
993
  );
 
994
  $vars['preview'] = drupal_build_form('views_ui_preview_form', $form_state);
 
995
 
 
996
  $vars['locked'] = NULL;
 
997
  if (isset($view->locked) && is_object($view->locked)) {
 
998
    $account = user_load($view->locked->uid);
 
999
    $vars['locked'] = theme('username', $account);
 
1000
    $vars['lock_age'] = format_interval(time() - $view->locked->updated);
 
1001
    $vars['break'] = url('admin/build/views/break-lock/' . $view->name);
 
1002
  }
 
1003
 
 
1004
  $vars['quick_links_raw'] = array(
 
1005
    array(
 
1006
      'title' => t('Export'),
 
1007
      'alt' => t("Export this view"),
 
1008
      'href' => "admin/build/views/export/$view->name",
 
1009
    ),
 
1010
    array(
 
1011
      'title' => t('Clone'),
 
1012
      'alt' => t("Create a copy of this view"),
 
1013
      'href' => "admin/build/views/clone/$view->name",
 
1014
    ),
 
1015
  );
 
1016
 
 
1017
  $paths = array();
 
1018
  foreach ($view->display as $id => $display) {
 
1019
    if (!empty($display->handler) && $display->handler->has_path()) {
 
1020
      $path = $display->handler->get_path();
 
1021
      if (strpos($path, '%') === FALSE && !isset($paths[$path])) {
 
1022
        $vars['quick_links_raw'][] = array(
 
1023
          'title' => t('View "!display"', array('!display' => $display->display_title)),
 
1024
          'alt' => t("Go to the real page for this display"),
 
1025
          'href' => $path,
 
1026
        );
 
1027
        // Displays can have the same path; no point in showing more than one link.
 
1028
        $paths[$path] = TRUE;
 
1029
      }
 
1030
    }
 
1031
  }
 
1032
 
 
1033
  $vars['quick_links'] = theme('links', $vars['quick_links_raw']);
 
1034
  views_add_css('views-admin');
 
1035
  views_add_css('views');
 
1036
  views_add_js('ajax');
 
1037
  drupal_add_js('misc/jquery.form.js');
 
1038
 
 
1039
  // Also add any js files required by plugins:
 
1040
  $plugins = views_fetch_plugin_data();
 
1041
  foreach ($plugins as $type => $type_plugins) {
 
1042
    foreach ($type_plugins as $name => $plugin) {
 
1043
      if (!empty($plugin['js'])) {
 
1044
        foreach ($plugin['js'] as $file) {
 
1045
          drupal_add_js($file);
 
1046
        }
 
1047
      }
 
1048
    }
 
1049
  }
 
1050
 
 
1051
  $settings = array('views' => array('ajax' => array(
 
1052
    'id' => '#views-ajax-pad',
 
1053
    'title' => '#views-ajax-title',
 
1054
    'defaultForm' => $vars['message'],
 
1055
  )));
 
1056
 
 
1057
  drupal_add_js($settings, 'setting');
 
1058
}
 
1059
 
 
1060
function template_preprocess_views_ui_edit_tab(&$vars) {
 
1061
  $view = $vars['view'];
 
1062
  $display = $vars['display'];
 
1063
  $plugin = $display->handler->definition;
 
1064
 
 
1065
  $top = $left = $middle = $right = '';
 
1066
 
 
1067
  // If this form was submitted it was already handled, so force it not to
 
1068
  // submit again.
 
1069
 
 
1070
  $vars['remove'] = '';
 
1071
  if (empty($plugin['no remove'])) {
 
1072
    if (!empty($_POST['form_id']) && $_POST['form_id'] == 'views_ui_remove_display_form') {
 
1073
      unset($_POST['form_id']);
 
1074
    }
 
1075
    $form_state = array('view' => &$view, 'display_id' => $display->id, 'ajax' => FALSE);
 
1076
    $vars['remove'] = drupal_build_form('views_ui_remove_display_form', $form_state);
 
1077
  }
 
1078
 
 
1079
  // basic fields
 
1080
  $vars['title'] = check_plain($display->display_title);
 
1081
  $vars['description'] = check_plain($plugin['help']);
 
1082
 
 
1083
  // Special fields if tihs is the default display.
 
1084
  $vars['default'] = ($display->id == 'default');
 
1085
  $vars['details_class'] = views_ui_item_css('details');
 
1086
  if (!empty($view->changed_sections['details'])) {
 
1087
    $vars['details_changed'] = TRUE;
 
1088
  }
 
1089
 
 
1090
  $tag = empty($view->tag) ? t('None') : $view->tag;
 
1091
  $vars['details'] = t('Tag') . ': ' . l($tag, "admin/build/views/nojs/details/$view->name", array('attributes' => array('class' => 'views-ajax-link')));
 
1092
 
 
1093
  // Calculate options from display plugin.
 
1094
  $options = $categories = array();
 
1095
  $display->handler->options_summary($categories, $options);
 
1096
 
 
1097
  // Build all of the options we were returned and put them into the
 
1098
  // category data fields.
 
1099
  foreach ($options as $id => $option) {
 
1100
    if (empty($categories[$option['category']]['data'])) {
 
1101
      $categories[$option['category']]['data'] = array();
 
1102
    }
 
1103
    $categories[$option['category']]['data'][$id] = array();
 
1104
    $data = &$categories[$option['category']]['data'][$id];
 
1105
    $data['content'] = '';
 
1106
    $data['links'] = '';
 
1107
    $data['overridden'] = FALSE;
 
1108
    $data['defaulted'] = FALSE;
 
1109
 
 
1110
    // If there are optional links, build them first so they float properly.
 
1111
    if (!empty($option['links'])) {
 
1112
      foreach ($option['links'] as $link_id => $link_value) {
 
1113
        $data['links'] .= $display->handler->option_link($link_value, $link_id, 'views-button-configure');
 
1114
      }
 
1115
    }
 
1116
    if (!empty($option['title'])) {
 
1117
      $data['content'] .= $option['title'] . ': ';
 
1118
    }
 
1119
 
 
1120
    $data['content'] .= $display->handler->option_link($option['value'], $id, '', empty($option['desc']) ? '' : $option['desc']);
 
1121
    if (!empty($display->handler->options['defaults'][$id])) {
 
1122
      $display_id = 'default';
 
1123
      $data['defaulted'] = TRUE;
 
1124
    }
 
1125
    else {
 
1126
      $display_id = $display->id;
 
1127
      if (!$display->handler->is_default_display()) {
 
1128
        if ($display->handler->defaultable_sections($id)) {
 
1129
          $data['overridden'] = TRUE;
 
1130
        }
 
1131
      }
 
1132
    }
 
1133
    $data['class'] = views_ui_item_css($display_id . '-' . $id);
 
1134
    if (!empty($view->changed_sections[$display_id . '-' . $id])) {
 
1135
      $data['changed'] = TRUE;
 
1136
    }
 
1137
  }
 
1138
 
 
1139
  $vars['categories'] = $categories;
 
1140
 
 
1141
  // Add a help icon
 
1142
  if (isset($plugin['help topic'])) {
 
1143
    $vars['display_help_icon'] = theme('advanced_help_topic', $plugin['module'], $plugin['help topic']);
 
1144
  }
 
1145
  else {
 
1146
    $vars['display_help_icon'] = '';
 
1147
  }
 
1148
 
 
1149
  // Fetch style plugin info because it has some effect on how/what we render.
 
1150
  $style_plugin = $display->handler->get_plugin();
 
1151
 
 
1152
  $vars['fields'] = '';
 
1153
  $vars['fields'] = theme('views_ui_edit_item', 'field', $view, $display, !($style_plugin && $style_plugin->uses_fields()));
 
1154
  $vars['relationships'] = theme('views_ui_edit_item', 'relationship', $view, $display);
 
1155
  $vars['arguments'] = theme('views_ui_edit_item', 'argument', $view, $display);
 
1156
  $vars['filters'] = theme('views_ui_edit_item', 'filter', $view, $display);
 
1157
  $vars['sorts'] = theme('views_ui_edit_item', 'sort', $view, $display);
 
1158
}
 
1159
 
 
1160
/**
 
1161
 * Generate the summary output for a single display to render in a tab.
 
1162
 */
 
1163
function views_ui_display_tab($view, $display) {
 
1164
  if (isset($display->handler)) {
 
1165
    $plugin = $display->handler->definition;
 
1166
  }
 
1167
  if (empty($plugin)) {
 
1168
    $title = isset($display->display_title) ? $display->display_title : t('Invalid');
 
1169
    return array($title, t("Error: Display @display refers to a plugin named '@plugin', but that plugin doesn't exist!", array('@display' => $display->id, '@plugin' => $display->display_plugin)));
 
1170
 
 
1171
    // @todo We can do a better 'plugin does not exist' tab.
 
1172
  }
 
1173
 
 
1174
  // The display should always be initialized prior to this call.
 
1175
  if (empty($display->handler)) {
 
1176
    return FALSE;
 
1177
  }
 
1178
 
 
1179
  $body = theme('views_ui_edit_tab', $view, $display);
 
1180
  return array($display->display_title, $body);
 
1181
}
 
1182
 
 
1183
/**
 
1184
 * Add information about a section to a display.
 
1185
 */
 
1186
function template_preprocess_views_ui_edit_item(&$vars) {
 
1187
  $type = $vars['type'];
 
1188
  $view = $vars['view'];
 
1189
  $display = $vars['display'];
 
1190
 
 
1191
  $types = views_object_types();
 
1192
 
 
1193
  $vars['overridden'] = FALSE;
 
1194
  $vars['defaulted'] = FALSE;
 
1195
 
 
1196
  if ($vars['no_fields']) {
 
1197
    $vars['title'] = $types[$type]['title'];
 
1198
    $vars['item_help_icon'] = theme('advanced_help_topic', 'views', $type);
 
1199
    $vars['rearrange'] = NULL;
 
1200
    $vars['add'] = NULL;
 
1201
    return;
 
1202
  }
 
1203
 
 
1204
  $vars['rearrange'] = l('<span>' . t('Rearrange') . '</span>', "admin/build/views/nojs/rearrange/$view->name/$display->id/$type", array('attributes' => array('class' => 'views-button-rearrange views-ajax-link', 'title' => t('Rearrange')), 'html' => true));
 
1205
 
 
1206
  $vars['add'] = l('<span>' . t('Add') . '</span>', "admin/build/views/nojs/add-item/$view->name/$display->id/$type", array('attributes' => array('class' => 'views-button-add views-ajax-link', 'title' => t('Add')), 'html' => true));
 
1207
 
 
1208
  if (!$display->handler->is_default_display()) {
 
1209
    if (!$display->handler->is_defaulted($types[$type]['plural'])) {
 
1210
      $vars['overridden'] = TRUE;
 
1211
    }
 
1212
    else {
 
1213
      $vars['defaulted'] = TRUE;
 
1214
    }
 
1215
  }
 
1216
 
 
1217
  $vars['title'] = l($types[$type]['title'], "admin/build/views/nojs/config-type/$view->name/$display->id/$type", array('attributes' => array('class' => 'views-ajax-link')));
 
1218
//  $vars['title'] = l($types[$type]['title'], "admin/build/views/nojs/config-type/$view->name/$display->id/$type", array('attributes' => array('class' => 'views-ajax-link')));
 
1219
 
 
1220
  $fields = array();
 
1221
 
 
1222
  static $relationships = NULL;
 
1223
  if (!isset($relationships)) {
 
1224
    // Get relationship labels
 
1225
    $relationships = array();
 
1226
    // @todo: get_handlers()
 
1227
    foreach ($display->handler->get_option('relationships') as $id => $relationship) {
 
1228
      $handler = views_get_handler($relationship['table'], $relationship['field'], 'relationship');
 
1229
      if (empty($handler)) {
 
1230
        continue;
 
1231
      }
 
1232
      $handler->init($view, $relationship);
 
1233
      $relationships[$id] = $handler->label();
 
1234
    }
 
1235
  }
 
1236
 
 
1237
  // @todo: get_handlers()
 
1238
  foreach ($display->handler->get_option($types[$type]['plural']) as $id => $field) {
 
1239
    $fields[$id] = array();
 
1240
 
 
1241
    $handler = views_get_handler($field['table'], $field['field'], $type);
 
1242
    if (empty($handler)) {
 
1243
      $fields[$id]['class'] = 'broken';
 
1244
      $fields[$id]['title'] = t("Error: handler for @table > @field doesn't exist!", array('@table' => $field['table'], '@field' => $field['field']));
 
1245
      $fields[$id]['info'] = '';
 
1246
      continue;
 
1247
    }
 
1248
    $handler->init($view, $field);
 
1249
 
 
1250
    $field_name = $handler->ui_name(TRUE);
 
1251
    if (!empty($field['relationship']) && !empty($relationships[$field['relationship']])) {
 
1252
      $field_name = '(' . $relationships[$field['relationship']] . ') ' . $field_name;
 
1253
    }
 
1254
 
 
1255
    $fields[$id]['title'] = l($field_name, "admin/build/views/nojs/config-item/$view->name/$display->id/$type/$id", array('attributes' => array('class' => 'views-ajax-link'), 'html' => TRUE));
 
1256
    $fields[$id]['class'] = views_ui_item_css($display->id . '-' . $type . '-' . $id);
 
1257
    if (!empty($view->changed_sections[$display->id . '-' . $type . '-' . $id])) {
 
1258
      $fields[$id]['changed'] = TRUE;
 
1259
    }
 
1260
    $fields[$id]['info'] = $handler->admin_summary();
 
1261
 
 
1262
    if ($handler->has_extra_options()) {
 
1263
      $fields[$id]['links'] = l('<span>' . t('Settings') . '</span>', "admin/build/views/nojs/config-item-extra/$view->name/$display->id/$type/$id", array('attributes' => array('class' => 'views-button-configure views-ajax-link', 'title' => t('Settings')), 'html' => true));
 
1264
    }
 
1265
 
 
1266
    if ($handler->needs_style_plugin()) {
 
1267
      $style_plugin = views_fetch_plugin_data('style', $handler->options['style_plugin']);
 
1268
      $style_title = empty($style_plugin['title']) ? t('Missing style plugin') : $style_plugin['title'];
 
1269
      $pid = $id . '-style-plugin';
 
1270
 
 
1271
      if (!empty($style_plugin['uses options'])) {
 
1272
        $fields[$pid]['links'] = l('<span>' . t('Change settings for this style') . '</span>', "admin/build/views/nojs/config-style/$view->name/$display->id/$type/$id", array('attributes' => array('class' => 'views-button-configure views-ajax-link', 'title' => t('Settings')), 'html' => true));
 
1273
      }
 
1274
 
 
1275
      $fields[$pid]['title'] = ' ' . t('&nbsp; Style: !style', array('!style' => l($style_title, "admin/build/views/nojs/change-style/$view->name/$display->id/$type/$id", array('attributes' => array('class' => 'views-ajax-link')))));
 
1276
      $fields[$pid]['class'] = views_ui_item_css($display->id . '-' . $type . '-' . $pid);
 
1277
      if (!empty($view->changed_sections[$display->id . '-' . $type . '-' . $pid])) {
 
1278
        $fields[$pid]['changed'] = TRUE;
 
1279
      }
 
1280
      $fields[$pid]['info'] = '';
 
1281
    }
 
1282
  }
 
1283
 
 
1284
  $vars['fields'] = $fields;
 
1285
  $vars['item_help_icon'] = theme('advanced_help_topic', 'views', $type);
 
1286
}
 
1287
 
 
1288
/**
 
1289
 * Regenerate the tabs for AJAX updates.
 
1290
 */
 
1291
function views_ui_regenerate_tabs(&$view, $display_id = NULL, $object = NULL) {
 
1292
  if (empty($display_id)) {
 
1293
    $displays = array_keys($view->display);
 
1294
  }
 
1295
  elseif (!is_array($display_id)) {
 
1296
    $displays = array($display_id);
 
1297
    if ($display_id != 'default') {
 
1298
      $displays[] = 'default';
 
1299
    }
 
1300
  }
 
1301
  else {
 
1302
    $displays = $display_id;
 
1303
  }
 
1304
 
 
1305
  if (!$view->set_display('default')) {
 
1306
    views_ajax_render(t('Invalid display id found while regenerating tabs'));
 
1307
  }
 
1308
 
 
1309
  if (!is_object($object)) {
 
1310
    $object = new stdClass();
 
1311
  }
 
1312
 
 
1313
  $object->replace = array();
 
1314
  foreach ($displays as $id) {
 
1315
    list($title, $body) = views_ui_display_tab($view, $view->display[$id]);
 
1316
    $object->replace['#views-tab-' . $id] = $body;
 
1317
    $object->replace['#views-tab-title-' . $id] = $title;
 
1318
  }
 
1319
 
 
1320
  if (!empty($view->changed)) {
 
1321
    $object->changed = TRUE;
 
1322
  }
 
1323
 
 
1324
  views_ajax_render($object);
 
1325
}
 
1326
 
 
1327
/**
 
1328
 * Provide standard buttons for the forms to make it easy. Also provide
 
1329
 * a hidden op operator because the forms plugin doesn't seem to properly
 
1330
 * provide which button was clicked.
 
1331
 */
 
1332
function views_ui_standard_form_buttons(&$form, &$form_state, $form_id, $name = NULL, $third = NULL, $submit = NULL) {
 
1333
  $form['buttons'] = array(
 
1334
    '#prefix' => '<div class="clear-block"><div class="form-buttons">',
 
1335
    '#suffix' => '</div></div>',
 
1336
  );
 
1337
 
 
1338
  if (empty($name)) {
 
1339
    $name = t('Update');
 
1340
  }
 
1341
  // remove default validate handler
 
1342
  $form['#validate'] = array();
 
1343
 
 
1344
  if (empty($form_state['ok_button'])) {
 
1345
    // but be sure submit button validates!
 
1346
    $form['buttons']['submit'] = array(
 
1347
      '#type' => 'submit',
 
1348
      '#value' => $name,
 
1349
      '#submit' => array($form_id . '_submit'),
 
1350
      '#validate' => array('views_ui_standard_submit', $form_id . '_validate'),
 
1351
    );
 
1352
  }
 
1353
 
 
1354
  $cancel_submit = function_exists($form_id . '_cancel') ? $form_id . '_cancel' : 'views_ui_standard_cancel';
 
1355
  $form['buttons']['cancel'] = array(
 
1356
    '#type' => 'submit',
 
1357
    '#value' => empty($form_state['ok_button']) ? t('Cancel') : t('Ok'),
 
1358
    '#submit' => array($cancel_submit),
 
1359
    '#validate' => array(),
 
1360
  );
 
1361
 
 
1362
  if ($third) {
 
1363
    if (empty($submit)) {
 
1364
      $submit = 'third';
 
1365
    }
 
1366
    $third_submit = function_exists($form_id . '_' . $submit) ? $form_id . '_' . $submit : 'views_ui_standard_cancel';
 
1367
 
 
1368
    $form['buttons'][$submit] = array(
 
1369
      '#type' => 'submit',
 
1370
      '#value' => $third,
 
1371
      '#validate' => array(),
 
1372
      '#submit' => array($third_submit),
 
1373
    );
 
1374
  }
 
1375
 
 
1376
  // Compatibility, to be removed later:
 
1377
  // We used to set these items on the form, but now we want them on the $form_state:
 
1378
  if (isset($form['#title'])) {
 
1379
    $form_state['title'] = $form['#title'];
 
1380
  }
 
1381
  if (isset($form['#help_topic'])) {
 
1382
    $form_state['help_topic'] = $form['#help_topic'];
 
1383
  }
 
1384
  if (isset($form['#help_module'])) {
 
1385
    $form_state['help_module'] = $form['#help_module'];
 
1386
  }
 
1387
  if (isset($form['#url'])) {
 
1388
    $form_state['url'] = $form['#url'];
 
1389
  }
 
1390
  if (isset($form['#js'])) {
 
1391
    if (!empty($form_state['js settings']) && is_array($form_state['js settings'])) {
 
1392
      $form_state['js settings'] = array_merge($form_state['js settings'], $form['#js']);
 
1393
    }
 
1394
    else {
 
1395
      $form_state['js settings'] = $form['#js'];
 
1396
    }
 
1397
  }
 
1398
  if (isset($form['#section'])) {
 
1399
    $form_state['#section'] = $form['#section'];
 
1400
  }
 
1401
  // Finally, we never want these cached -- our object cache does that for us.
 
1402
  $form['#no_cache'] = TRUE;
 
1403
 
 
1404
  // If this isn't an ajaxy form, then we want to set the title.
 
1405
  if (!empty($form['#title'])) {
 
1406
    drupal_set_title($form['#title']);
 
1407
  }
 
1408
  views_add_css('views-admin');
 
1409
}
 
1410
 
 
1411
/**
 
1412
 * Basic submit handler applicable to all 'standard' forms
 
1413
 */
 
1414
function views_ui_standard_submit($form, &$form_state) {
 
1415
  if (!empty($form['#section'])) {
 
1416
    $form_state['view']->changed_sections[$form['#section']] = TRUE;
 
1417
  }
 
1418
}
 
1419
 
 
1420
/**
 
1421
 * Submit handler for cancel button
 
1422
 */
 
1423
function views_ui_standard_cancel($form, &$form_state) {
 
1424
  $form_state['redirect'] = 'admin/build/views/edit/' . $form_state['view']->name;
 
1425
}
 
1426
 
 
1427
// --------------------------------------------------------------------------
 
1428
// Various subforms for editing the pieces of a view.
 
1429
 
 
1430
function views_ui_ajax_forms($key = NULL) {
 
1431
  $forms = array(
 
1432
    'display' => array(
 
1433
      'form_id' => 'views_ui_edit_display_form',
 
1434
      'args' => array('section'),
 
1435
    ),
 
1436
    'remove-display' => array(
 
1437
      'form_id' => 'views_ui_remove_display_form',
 
1438
      'args' => array(),
 
1439
    ),
 
1440
    'config-type' => array(
 
1441
      'form_id' => 'views_ui_config_type_form',
 
1442
      'args' => array('type'),
 
1443
    ),
 
1444
    'rearrange' => array(
 
1445
      'form_id' => 'views_ui_rearrange_form',
 
1446
      'args' => array('type'),
 
1447
    ),
 
1448
    'add-item' => array(
 
1449
      'form_id' => 'views_ui_add_item_form',
 
1450
      'args' => array('type'),
 
1451
    ),
 
1452
    'config-item' => array(
 
1453
      'form_id' => 'views_ui_config_item_form',
 
1454
      'args' => array('type', 'id'),
 
1455
    ),
 
1456
    'config-item-extra' => array(
 
1457
      'form_id' => 'views_ui_config_item_extra_form',
 
1458
      'args' => array('type', 'id'),
 
1459
    ),
 
1460
    'change-style' => array(
 
1461
      'form_id' => 'views_ui_change_style_form',
 
1462
      'args' => array('type', 'id'),
 
1463
    ),
 
1464
    'config-style' => array(
 
1465
      'form_id' => 'views_ui_config_style_form',
 
1466
      'args' => array('type', 'id'),
 
1467
    ),
 
1468
  );
 
1469
 
 
1470
  if ($key) {
 
1471
    return !empty($forms[$key]) ? $forms[$key] : NULL;
 
1472
  }
 
1473
 
 
1474
  return $forms;
 
1475
}
 
1476
 
 
1477
/**
 
1478
 * Build a form identifier that we can use to see if one form
 
1479
 * is the same as another. Since the arguments differ slightly
 
1480
 * we do a lot of spiffy concenation here.
 
1481
 */
 
1482
function views_ui_build_identifier($key, $view, $display_id, $args) {
 
1483
  $form = views_ui_ajax_forms($key);
 
1484
  $identifier = implode('-', array($key, $view->name, $display_id));
 
1485
 
 
1486
  foreach ($form['args'] as $id) {
 
1487
    $arg = (!empty($args)) ? array_shift($args) : NULL;
 
1488
    $identifier .= '-' . $arg;
 
1489
  }
 
1490
  return $identifier;
 
1491
}
 
1492
 
 
1493
/**
 
1494
 * Build up a $form_state object suitable for use with drupal_build_form
 
1495
 * based on known information about a form.
 
1496
 */
 
1497
function views_ui_build_form_state($js, $key, &$view, $display_id, $args) {
 
1498
  $form = views_ui_ajax_forms($key);
 
1499
  // Build up form state
 
1500
  $form_state = array(
 
1501
    'form_key' => $key,
 
1502
    'form_id' => $form['form_id'],
 
1503
    'view' => &$view,
 
1504
    'ajax' => $js,
 
1505
    'display_id' => $display_id,
 
1506
    'no_redirect' => TRUE,
 
1507
  );
 
1508
 
 
1509
  foreach ($form['args'] as $id) {
 
1510
    $form_state[$id] = (!empty($args)) ? array_shift($args) : NULL;
 
1511
  }
 
1512
 
 
1513
  return $form_state;
 
1514
}
 
1515
 
 
1516
/**
 
1517
 * Create the URL for one of our standard AJAX forms based upon known
 
1518
 * information about the form.
 
1519
 */
 
1520
function views_ui_build_form_url($form_state) {
 
1521
  $form = views_ui_ajax_forms($form_state['form_key']);
 
1522
  $ajax = empty($form_state['ajax']) ? 'nojs' : 'ajax';
 
1523
  $name = $form_state['view']->name;
 
1524
  $url = "admin/build/views/$ajax/$form_state[form_key]/$name/$form_state[display_id]";
 
1525
  foreach ($form['args'] as $arg) {
 
1526
    $url .= '/' . $form_state[$arg];
 
1527
  }
 
1528
  return $url;
 
1529
}
 
1530
 
 
1531
/**
 
1532
 * Add another form to the stack; clicking 'update' will go to this form
 
1533
 * rather than closing the ajax pad.
 
1534
 */
 
1535
function views_ui_add_form_to_stack($key, &$view, $display_id, $args, $top = FALSE) {
 
1536
  if (empty($view->stack)) {
 
1537
    $view->stack = array();
 
1538
  }
 
1539
 
 
1540
  $stack = array(views_ui_build_identifier($key, $view, $display_id, $args), $key, &$view, $display_id, $args);
 
1541
  if ($top) {
 
1542
    array_unshift($view->stack, $stack);
 
1543
  }
 
1544
  else {
 
1545
    $view->stack[] = $stack;
 
1546
  }
 
1547
}
 
1548
 
 
1549
/**
 
1550
 * Generic entry point to handle forms.
 
1551
 *
 
1552
 * We do this for consistency and to make it easy to chain forms
 
1553
 * together. This only works for forms that use both $view
 
1554
 * and $display_id, so we have a couple of ajax forms that we don't
 
1555
 * use with this system.
 
1556
 */
 
1557
function views_ui_ajax_form($js, $key, &$view, $display_id) {
 
1558
  $form = views_ui_ajax_forms($key);
 
1559
  if (empty($form)) {
 
1560
    return drupal_not_found();
 
1561
  }
 
1562
 
 
1563
  views_include('ajax');
 
1564
  $args = func_get_args();
 
1565
  // Remove the known args
 
1566
  array_splice($args, 0, 4);
 
1567
 
 
1568
  $form_state = views_ui_build_form_state($js, $key, $view, $display_id, $args);
 
1569
  // check to see if this is the top form of the stack. If it is, pop
 
1570
  // it off; if it isn't, the user clicked somewhere else and the stack is
 
1571
  // now irrelevant.
 
1572
  if (!empty($view->stack)) {
 
1573
    $identifier = views_ui_build_identifier($key, $view, $display_id, $args);
 
1574
    $top = array_shift($view->stack);
 
1575
    if (array_shift($top) != $identifier) {
 
1576
      $view->stack = array();
 
1577
    }
 
1578
  }
 
1579
 
 
1580
  $output = views_ajax_form_wrapper($form_state['form_id'], $form_state);
 
1581
 
 
1582
  if (!$output) {
 
1583
    // Sometimes we need to re-generate the form for multi-step type operations.
 
1584
    $object = NULL;
 
1585
    if (!empty($view->stack)) {
 
1586
      $stack = $view->stack; // copy so the next shift doesn't break the array
 
1587
      $top = array_shift($stack);
 
1588
      $top[0] = $js; // change identifier into $js setting
 
1589
      $form_state = call_user_func_array('views_ui_build_form_state', $top);
 
1590
      $form_state['input'] = array(); // this is a new form, make sure it
 
1591
      // doesn't try to inherit $_POST info.
 
1592
      if (!$js) {
 
1593
        return drupal_goto(views_ui_build_form_url($form_state));
 
1594
      }
 
1595
      $object = views_ajax_form_wrapper($form_state['form_id'], $form_state);
 
1596
      $object->url = url(views_ui_build_form_url($form_state));
 
1597
    }
 
1598
    else if (!$js) {
 
1599
      // if nothing on the stack, non-js forms just go back to the main view editor.
 
1600
      return drupal_goto("admin/build/views/edit/$view->name");
 
1601
    }
 
1602
    // regenerate all tabs because changes to the default tab could ripple.
 
1603
    return views_ui_regenerate_tabs($view, NULL, $object);
 
1604
  }
 
1605
 
 
1606
  return ($js) ? views_ajax_render($output) : $output;
 
1607
}
 
1608
 
 
1609
/**
 
1610
 * AJAX callback to add a display.
 
1611
 */
 
1612
function views_ui_add_display($js, $view) {
 
1613
  views_include('ajax');
 
1614
  $form_state = array(
 
1615
    'view' => &$view,
 
1616
    'ajax' => $js,
 
1617
  );
 
1618
 
 
1619
  $output = views_ajax_form_wrapper('views_ui_add_display_form', $form_state);
 
1620
 
 
1621
  if ($js) {
 
1622
    // If we don't have an output object, it was submitted. Set up the submission.
 
1623
    if (empty($output)) {
 
1624
      $id = $form_state['id'];
 
1625
 
 
1626
      // Make sure the new display is active
 
1627
      if (!$view->set_display('default')) {
 
1628
        views_ajax_render(t('Unable to initialize default display'));
 
1629
      }
 
1630
 
 
1631
      // Render the new display
 
1632
      list($title, $body) = views_ui_display_tab($view, $view->display[$id]);
 
1633
 
 
1634
      // Instruct the javascript on the browser to render the new tab.
 
1635
      $output = new stdClass;
 
1636
      $output->tab = array('#views-tab-' . $id => array('title' => $title, 'body' => $body));
 
1637
    }
 
1638
    // Render the command object. This automatically exits.
 
1639
    views_ajax_render($output);
 
1640
  }
 
1641
 
 
1642
  // But the non-js variant will return output if it didn't redirect us.
 
1643
  return $output;
 
1644
}
 
1645
 
 
1646
/**
 
1647
 * Form to add a display to a view.
 
1648
 */
 
1649
function views_ui_add_display_form(&$form_state) {
 
1650
  $view = &$form_state['view'];
 
1651
 
 
1652
  $form['display']['display'] = array(
 
1653
    '#type' => 'select',
 
1654
    '#options' => views_fetch_plugin_names('display'),
 
1655
    '#default_value' => 'page',
 
1656
  );
 
1657
 
 
1658
  $form['display']['add_display'] = array(
 
1659
    '#type' => 'submit',
 
1660
    '#value' => t('Add display'),
 
1661
    '#submit' => array('views_ui_add_display_form_submit'),
 
1662
  );
 
1663
 
 
1664
  $form['#id'] = 'views-add-display-form';
 
1665
  $form['#attributes'] = array('class' => 'views-ajax-form');
 
1666
  $form['#action'] = url("admin/build/views/nojs/add-display/$view->name");
 
1667
 
 
1668
  return $form;
 
1669
}
 
1670
 
 
1671
/**
 
1672
 * Submit handler to add a display to a view.
 
1673
 */
 
1674
function views_ui_add_display_form_submit($form, &$form_state) {
 
1675
  // Create the new display
 
1676
  $plugin = $form_state['values']['display'];
 
1677
  $form_state['id'] = $form_state['view']->add_display($plugin);
 
1678
 
 
1679
  // Store in cache
 
1680
  views_ui_cache_set($form_state['view']);
 
1681
 
 
1682
  // Send it back
 
1683
  $form_state['redirect'] = array('admin/build/views/edit/' . $form_state['view']->name, NULL, 'views-tab-' . $form_state['id']);
 
1684
}
 
1685
 
 
1686
/**
 
1687
 * Form to remove a display from a view.
 
1688
 */
 
1689
function views_ui_remove_display_form(&$form_state) {
 
1690
  $view = &$form_state['view'];
 
1691
  $display_id = $form_state['display_id'];
 
1692
 
 
1693
  if (empty($view->display[$display_id]->deleted)) {
 
1694
    $form['display'] = array(
 
1695
      '#prefix' => '<div class="display-button remove-display">',
 
1696
      '#suffix' => '</div>',
 
1697
    );
 
1698
    $form['remove_display'] = array(
 
1699
      '#type' => 'submit',
 
1700
      '#value' => t('Remove display'),
 
1701
      '#submit' => array('views_ui_remove_display_form_submit'),
 
1702
    );
 
1703
  }
 
1704
  else {
 
1705
    $form['display'] = array(
 
1706
      '#prefix' => '<div class="display-button restore-display">',
 
1707
      '#suffix' => '</div>',
 
1708
    );
 
1709
    $form['restore_display'] = array(
 
1710
      '#type' => 'submit',
 
1711
      '#value' => t('Restore display'),
 
1712
      '#submit' => array('views_ui_remove_display_form_restore'),
 
1713
    );
 
1714
  }
 
1715
  $form['#action'] = url("admin/build/views/nojs/remove-display/$view->name/$display_id");
 
1716
  $form['#attributes'] = array('class' => 'views-ajax-form');
 
1717
 
 
1718
  return $form;
 
1719
}
 
1720
 
 
1721
/**
 
1722
 * Submit handler to add a remove to a display from a view.
 
1723
 */
 
1724
function views_ui_remove_display_form_submit($form, &$form_state) {
 
1725
  // Create the new display
 
1726
  $plugin = views_fetch_plugin_data('display', $form_state['view']->display[$form_state['display_id']]->display_plugin);
 
1727
  if (empty($plugin['no remove'])) {
 
1728
    $id = $form_state['display_id'];
 
1729
    $form_state['view']->display[$id]->deleted = TRUE;
 
1730
 
 
1731
    // Store in cache
 
1732
    views_ui_cache_set($form_state['view']);
 
1733
  }
 
1734
}
 
1735
 
 
1736
/**
 
1737
 * Submit handler to add a restore a removed display to a view.
 
1738
 */
 
1739
function views_ui_remove_display_form_restore($form, &$form_state) {
 
1740
  // Create the new display
 
1741
  $id = $form_state['display_id'];
 
1742
  $form_state['view']->display[$id]->deleted = FALSE;
 
1743
 
 
1744
  // Store in cache
 
1745
  views_ui_cache_set($form_state['view']);
 
1746
}
 
1747
 
 
1748
/**
 
1749
 * Page callback to display analysis information on a view.
 
1750
 */
 
1751
function views_ui_analyze_view($js, $view) {
 
1752
  views_include('ajax');
 
1753
  $form_state = array(
 
1754
    'view' => &$view,
 
1755
    'ajax' => $js,
 
1756
  );
 
1757
 
 
1758
  $output = views_ajax_form_wrapper('views_ui_analyze_view_form', $form_state);
 
1759
 
 
1760
  if ($js) {
 
1761
    // If we don't have an output object, it was submitted. Set up the submission.
 
1762
    if (empty($output)) {
 
1763
      return views_ui_regenerate_tabs($view);
 
1764
    }
 
1765
    return views_ajax_render($output);
 
1766
 
 
1767
  }
 
1768
  return $output;
 
1769
}
 
1770
 
 
1771
/**
 
1772
 * This form doesn't particularly do much; it's really just providing a link
 
1773
 * but a button seems like it would be nicer here.
 
1774
 *
 
1775
 * It has no submit or anything, as we will never actually submit this form
 
1776
 * where the form is placed.
 
1777
 */
 
1778
function views_ui_analyze_view_button(&$form_state, $view) {
 
1779
  $form['#action'] = url("admin/build/views/nojs/analyze/$view->name");
 
1780
  $form['#attributes'] = array('class' => 'views-ajax-form');
 
1781
  $form['submit'] = array(
 
1782
    '#type' => 'submit',
 
1783
    '#value' => t('Analyze'),
 
1784
  );
 
1785
 
 
1786
  return $form;
 
1787
}
 
1788
 
 
1789
/**
 
1790
 * Form constructor callback to display analysis information on a view
 
1791
 */
 
1792
function views_ui_analyze_view_form(&$form_state) {
 
1793
  $view = &$form_state['view'];
 
1794
 
 
1795
  $form['#title'] = t('View analysis');
 
1796
  $form['#section'] = 'analyze';
 
1797
 
 
1798
  views_include('analyze');
 
1799
  $messages = views_analyze_view($view);
 
1800
 
 
1801
  $form['analysis'] = array(
 
1802
    '#prefix' => '<div class="form-item">',
 
1803
    '#suffix' => '</div>',
 
1804
    '#value' => views_analyze_format_result($view, $messages),
 
1805
  );
 
1806
 
 
1807
  // Inform the standard button function that we want an OK button.
 
1808
  $form_state['ok_button'] = TRUE;
 
1809
  views_ui_standard_form_buttons($form, $form_state, 'views_ui_analyze_view_form');
 
1810
  return $form;
 
1811
}
 
1812
 
 
1813
/**
 
1814
 * Submit handler for views_ui_analyze_view_form
 
1815
 */
 
1816
function views_ui_analyze_view_form_submit($form, &$form_state) {
 
1817
  $form_state['redirect'] = 'admin/build/views/edit/' . $form_state['view']->name;
 
1818
}
 
1819
 
 
1820
/**
 
1821
 * Page callback to edit details of a view.
 
1822
 */
 
1823
function views_ui_edit_details($js, $view) {
 
1824
  views_include('ajax');
 
1825
  $form_state = array(
 
1826
    'view' => &$view,
 
1827
    'ajax' => $js,
 
1828
  );
 
1829
 
 
1830
  $output = views_ajax_form_wrapper('views_ui_edit_details_form', $form_state);
 
1831
 
 
1832
  if ($js) {
 
1833
    // If we don't have an output object, it was submitted. Set up the submission.
 
1834
    if (empty($output)) {
 
1835
      return views_ui_regenerate_tabs($view);
 
1836
    }
 
1837
    return views_ajax_render($output);
 
1838
 
 
1839
  }
 
1840
  return $output;
 
1841
}
 
1842
 
 
1843
/**
 
1844
 * Form constructor callback to edit details of a view
 
1845
 */
 
1846
function views_ui_edit_details_form(&$form_state) {
 
1847
  $view = &$form_state['view'];
 
1848
 
 
1849
  $form['#title'] = t('View details');
 
1850
  $form['#section'] = 'details';
 
1851
 
 
1852
  $form['description'] = array(
 
1853
    '#type' => 'textfield',
 
1854
    '#title' => t('View description'),
 
1855
    '#description' => t('This description will appear on the Views administrative UI to tell you what the view is about.'),
 
1856
    '#default_value' => $view->description,
 
1857
  );
 
1858
 
 
1859
  $form['tag'] = array(
 
1860
    '#type' => 'textfield',
 
1861
    '#title' => t('View tag'),
 
1862
    '#description' => t('Enter an optional tag for this view; it is used only to help sort views on the administrative page.'),
 
1863
    '#default_value' => $view->tag,
 
1864
    '#autocomplete_path' => 'admin/views/ajax/autocomplete/tag',
 
1865
  );
 
1866
 
 
1867
  views_ui_standard_form_buttons($form, $form_state, 'views_ui_edit_details_form');
 
1868
  return $form;
 
1869
}
 
1870
 
 
1871
/**
 
1872
 * Submit handler for views_ui_edit_details_form
 
1873
 */
 
1874
function views_ui_edit_details_form_submit($form, &$form_state) {
 
1875
  $form_state['view']->description = $form_state['values']['description'];
 
1876
  $form_state['view']->tag = $form_state['values']['tag'];
 
1877
  views_ui_cache_set($form_state['view']);
 
1878
  $form_state['redirect'] = 'admin/build/views/edit/' . $form_state['view']->name;
 
1879
}
 
1880
 
 
1881
/**
 
1882
 * Form constructor callback to edit display of a view
 
1883
 */
 
1884
function views_ui_edit_display_form(&$form_state) {
 
1885
  $view = &$form_state['view'];
 
1886
  $display_id = $form_state['display_id'];
 
1887
  $section = $form_state['section'];
 
1888
 
 
1889
  if (!$view->set_display($display_id)) {
 
1890
    views_ajax_render(t('Invalid display id @display', array('@display' => $display_id)));
 
1891
  }
 
1892
  $display = &$view->display[$display_id];
 
1893
 
 
1894
  // Get form from the handler.
 
1895
  $display->handler->options_form($form, $form_state);
 
1896
  $name = NULL;
 
1897
  if (isset($form_state['update_name'])) {
 
1898
    $name = $form_state['update_name'];
 
1899
  }
 
1900
 
 
1901
  views_ui_standard_form_buttons($form, $form_state, 'views_ui_edit_display_form', $name);
 
1902
  return $form;
 
1903
}
 
1904
 
 
1905
/**
 
1906
 * Validate handler for views_ui_edit_display_form
 
1907
 */
 
1908
function views_ui_edit_display_form_validate($form, &$form_state) {
 
1909
  $display = &$form_state['view']->display[$form_state['display_id']];
 
1910
  $display->handler->options_validate($form, $form_state);
 
1911
}
 
1912
 
 
1913
/**
 
1914
 * Submit handler for views_ui_edit_display_form
 
1915
 */
 
1916
function views_ui_edit_display_form_submit($form, &$form_state) {
 
1917
  $display = &$form_state['view']->display[$form_state['display_id']];
 
1918
  $display->handler->options_submit($form, $form_state);
 
1919
 
 
1920
  views_ui_cache_set($form_state['view']);
 
1921
}
 
1922
 
 
1923
/**
 
1924
 * Override handler for views_ui_edit_display_form
 
1925
 */
 
1926
function views_ui_edit_display_form_override($form, &$form_state) {
 
1927
  $display = &$form_state['view']->display[$form_state['display_id']];
 
1928
  $display->handler->options_override($form, $form_state);
 
1929
 
 
1930
  views_ui_cache_set($form_state['view']);
 
1931
  $form_state['rerender'] = TRUE;
 
1932
  $form_state['rebuild'] = TRUE;
 
1933
}
 
1934
/**
 
1935
 * Form to config items in the views UI.
 
1936
 */
 
1937
function views_ui_config_type_form(&$form_state) {
 
1938
  $view = &$form_state['view'];
 
1939
  $display_id = $form_state['display_id'];
 
1940
  $type = $form_state['type'];
 
1941
 
 
1942
  $types = views_object_types();
 
1943
  if (!$view->set_display($display_id)) {
 
1944
    views_ajax_render(t('Invalid display id @display', array('@display' => $display_id)));
 
1945
  }
 
1946
  $display = &$view->display[$display_id];
 
1947
  $form['#title'] = check_plain($display->display_title) . ': ';
 
1948
  $form['#title'] .= t('Configure @type', array('@type' => $types[$type]['ltitle']));
 
1949
  $form['#section'] = $display_id . 'config-item';
 
1950
 
 
1951
  if ($display->handler->defaultable_sections($types[$type]['plural'])) {
 
1952
    $form_state['section'] = $types[$type]['plural'];
 
1953
    $display->handler->add_override_button($form, $form_state, $form_state['section']);
 
1954
  }
 
1955
 
 
1956
  if (!empty($types[$type]['options']) && function_exists($types[$type]['options'])) {
 
1957
    $options = $type . '_options';
 
1958
    $form[$options] = array('#tree' => TRUE);
 
1959
    $types[$type]['options']($form, $form_state);
 
1960
  }
 
1961
 
 
1962
  $name = NULL;
 
1963
  if (isset($form_state['update_name'])) {
 
1964
    $name = $form_state['update_name'];
 
1965
  }
 
1966
 
 
1967
  views_ui_standard_form_buttons($form, $form_state, 'views_ui_config_type_form', $name);
 
1968
  return $form;
 
1969
}
 
1970
 
 
1971
/**
 
1972
 * Submit handler for type configuration form
 
1973
 */
 
1974
function views_ui_config_type_form_submit($form, &$form_state) {
 
1975
  $types = views_object_types();
 
1976
  $display = &$form_state['view']->display[$form_state['display_id']];
 
1977
 
 
1978
  // Store in cache
 
1979
  views_ui_cache_set($form_state['view']);
 
1980
}
 
1981
 
 
1982
/**
 
1983
 * Configure settings particular to filters.
 
1984
 */
 
1985
function views_ui_config_filters_form(&$form, &$form_state) {
 
1986
 
 
1987
}
 
1988
 
 
1989
/**
 
1990
 * Form to rearrange items in the views UI.
 
1991
 */
 
1992
function views_ui_rearrange_form(&$form_state) {
 
1993
  $view = &$form_state['view'];
 
1994
  $display_id = $form_state['display_id'];
 
1995
  $type = $form_state['type'];
 
1996
 
 
1997
  $types = views_object_types();
 
1998
  if (!$view->set_display($display_id)) {
 
1999
    views_ajax_render(t('Invalid display id @display', array('@display' => $display_id)));
 
2000
  }
 
2001
  $display = &$view->display[$display_id];
 
2002
  $form['#title'] = check_plain($display->display_title) . ': ';
 
2003
  $form['#title'] .= t('Rearrange @type', array('@type' => $types[$type]['ltitle']));
 
2004
  $form['#section'] = $display_id . 'rearrange-item';
 
2005
 
 
2006
  if ($display->handler->defaultable_sections($types[$type]['plural'])) {
 
2007
    $form_state['section'] = $types[$type]['plural'];
 
2008
    $display->handler->add_override_button($form, $form_state, $form_state['section']);
 
2009
  }
 
2010
 
 
2011
  $count = 0;
 
2012
 
 
2013
  // Get relationship labels
 
2014
  $relationships = array();
 
2015
  // @todo: get_handlers()
 
2016
  foreach ($display->handler->get_option('relationships') as $id => $relationship) {
 
2017
    $handler = views_get_handler($relationship['table'], $relationship['field'], 'relationship');
 
2018
    if (empty($handler)) {
 
2019
      continue;
 
2020
    }
 
2021
    $handler->init($view, $relationship);
 
2022
    $relationships[$id] = $handler->label();
 
2023
  }
 
2024
 
 
2025
  // @todo: get_handlers()
 
2026
  foreach ($display->handler->get_option($types[$type]['plural']) as $id => $field) {
 
2027
    $form[$id] = array('#tree' => TRUE);
 
2028
    $form[$id]['weight'] = array(
 
2029
      '#type' => 'weight',
 
2030
      '#delta' => 25,
 
2031
      '#default_value' => ++$count,
 
2032
    );
 
2033
    $handler = views_get_handler($field['table'], $field['field'], $type);
 
2034
    if ($handler) {
 
2035
      $handler->init($view, $field);
 
2036
      $name = $handler->ui_name() . ' ' . $handler->admin_summary();
 
2037
      if (!empty($field['relationship']) && !empty($relationships[$field['relationship']])) {
 
2038
        $name = '(' . $relationships[$field['relationship']] . ') ' . $name;
 
2039
      }
 
2040
 
 
2041
      $form[$id]['name'] = array(
 
2042
        '#value' => $name,
 
2043
      );
 
2044
    }
 
2045
    else {
 
2046
      $form[$id]['name'] = array('#value' => t('Broken field @id', array('@id' => $id)));
 
2047
    }
 
2048
    $form[$id]['removed'] = array(
 
2049
      '#type' => 'checkbox',
 
2050
      '#id' => 'views-removed-' . $id,
 
2051
      '#attributes' => array('class' => 'views-remove-checkbox'),
 
2052
      '#default_value' => 0,
 
2053
    );
 
2054
  }
 
2055
 
 
2056
  // Add javascript settings that will be added via $.extend for tabledragging
 
2057
  $form['#js']['tableDrag']['arrange']['weight'][0] = array(
 
2058
    'target' => 'weight',
 
2059
    'source' => NULL,
 
2060
    'relationship' => 'sibling',
 
2061
    'action' => 'order',
 
2062
    'hidden' => TRUE,
 
2063
    'limit' => 0,
 
2064
  );
 
2065
 
 
2066
  $name = NULL;
 
2067
  if (isset($form_state['update_name'])) {
 
2068
    $name = $form_state['update_name'];
 
2069
  }
 
2070
 
 
2071
  views_ui_standard_form_buttons($form, $form_state, 'views_ui_rearrange_form');
 
2072
  return $form;
 
2073
}
 
2074
 
 
2075
/**
 
2076
 * Turn the rearrange form into a proper table
 
2077
 */
 
2078
function theme_views_ui_rearrange_form($form) {
 
2079
  $rows = array();
 
2080
  foreach (element_children($form) as $id) {
 
2081
    if (isset($form[$id]['name'])) {
 
2082
      $row = array();
 
2083
      $row[] = drupal_render($form[$id]['name']);
 
2084
      $form[$id]['weight']['#attributes']['class'] = 'weight';
 
2085
      $row[] = drupal_render($form[$id]['weight']);
 
2086
      $row[] = drupal_render($form[$id]['removed']) . l('<span>' . t('Remove') . '</span>', 'javascript:void()', array('attributes' => array('id' => 'views-remove-link-' . $id, 'class' => 'views-button-remove views-remove-link', 'alt' => t('Remove this item'), 'title' => t('Remove this item')), 'html' => true));
 
2087
 
 
2088
      $rows[] = array('data' => $row, 'class' => 'draggable', 'id' => 'views-row-' . $id);
 
2089
    }
 
2090
  }
 
2091
  if (empty($rows)) {
 
2092
    $rows[] = array(array('data' => t('No fields available.'), 'colspan' => '2'));
 
2093
  }
 
2094
 
 
2095
  $header = array('', t('Weight'), t('Remove'));
 
2096
  drupal_add_tabledrag('arrange', 'order', 'sibling', 'weight');
 
2097
  $output = drupal_render($form['override']);
 
2098
  $output .= theme('table', $header, $rows, array('id' => 'arrange'));
 
2099
  $output .= drupal_render($form);
 
2100
  return $output;
 
2101
 
 
2102
}
 
2103
 
 
2104
/**
 
2105
 * Submit handler for rearranging form
 
2106
 */
 
2107
function views_ui_rearrange_form_submit($form, &$form_state) {
 
2108
  $types = views_object_types();
 
2109
  $display = &$form_state['view']->display[$form_state['display_id']];
 
2110
 
 
2111
  $old_fields = $display->handler->get_option($types[$form_state['type']]['plural']);
 
2112
  $new_fields = $order = array();
 
2113
 
 
2114
  // Make an array with the weights
 
2115
  foreach ($form_state['values'] as $field => $info) {
 
2116
    // add each value that is a field with a weight to our list, but only if
 
2117
    // it has had its 'removed' checkbox checked.
 
2118
    if (is_array($info) && isset($info['weight']) && empty($info['removed'])) {
 
2119
      $order[$field] = $info['weight'];
 
2120
    }
 
2121
  }
 
2122
 
 
2123
  // Sort the array
 
2124
  asort($order);
 
2125
 
 
2126
  // Create a new list of fields in the new order.
 
2127
  foreach (array_keys($order) as $field) {
 
2128
    $new_fields[$field] = $old_fields[$field];
 
2129
  }
 
2130
  $display->handler->set_option($types[$form_state['type']]['plural'], $new_fields);
 
2131
 
 
2132
  // Store in cache
 
2133
  views_ui_cache_set($form_state['view']);
 
2134
}
 
2135
 
 
2136
/**
 
2137
 * Form to add_item items in the views UI.
 
2138
 */
 
2139
function views_ui_add_item_form(&$form_state) {
 
2140
  $view = &$form_state['view'];
 
2141
  $display_id = $form_state['display_id'];
 
2142
  $type = $form_state['type'];
 
2143
 
 
2144
  if (!$view->set_display($display_id)) {
 
2145
    views_ajax_render(t('Invalid display id @display', array('@display' => $display_id)));
 
2146
  }
 
2147
  $display = &$view->display[$display_id];
 
2148
 
 
2149
  $types = views_object_types();
 
2150
  $form['#title'] = check_plain($display->display_title) . ': ';
 
2151
  $form['#title'] .= t('Add @type', array('@type' => $types[$type]['ltitle']));
 
2152
  $form['#section'] = $display_id . 'add-item';
 
2153
 
 
2154
  // Figure out all the base tables allowed based upon what the relationships provide.
 
2155
  $base_tables = $view->get_base_tables();
 
2156
  $options = views_fetch_fields(array_keys($base_tables), $type);
 
2157
 
 
2158
  if (!empty($options)) {
 
2159
    $groups = array('all' => t('<All>'));
 
2160
    $form['group'] = array(
 
2161
      '#type' => 'select',
 
2162
      '#title' => t('Groups'),
 
2163
      '#options' => array(),
 
2164
      '#attributes' => array('class' => 'views-master-dependent'),
 
2165
    );
 
2166
 
 
2167
    $form['name'] = array(
 
2168
      '#prefix' => '<div class="views-radio-box form-checkboxes">',
 
2169
      '#suffix' => '</div>',
 
2170
      '#tree' => TRUE,
 
2171
      '#default_value' => 'all',
 
2172
    );
 
2173
 
 
2174
    foreach ($options as $key => $option) {
 
2175
      $group = preg_replace('/[^a-z0-9]/', '-', strtolower($option['group']));
 
2176
      $groups[$group] = $option['group'];
 
2177
      $form['name'][$key] = array(
 
2178
        '#prefix' => '<div class="views-dependent-all views-dependent-' . $group . '">',
 
2179
        '#suffix' => '</div>',
 
2180
        '#type' => 'checkbox',
 
2181
        '#title' => t('!group: !field', array('!group' => $option['group'], '!field' => $option['title'])),
 
2182
        '#description' => $option['help'],
 
2183
        '#return_value' => $key,
 
2184
      );
 
2185
    }
 
2186
    $form['group']['#options'] = $groups;
 
2187
  }
 
2188
  else {
 
2189
    $form['markup'] = array(
 
2190
      '#value' => '<div class="form-item">' . t('There are no @types available to add.', array('@types' =>  $types[$type]['ltitle'])) . '</div>',
 
2191
    );
 
2192
  }
 
2193
  views_ui_standard_form_buttons($form, $form_state, 'views_ui_add_item_form', t('Add'));
 
2194
 
 
2195
  return $form;
 
2196
}
 
2197
 
 
2198
/**
 
2199
 * Submit handler for adding new item(s) to a view.
 
2200
 */
 
2201
function views_ui_add_item_form_submit($form, &$form_state) {
 
2202
  $type = $form_state['type'];
 
2203
  $types = views_object_types();
 
2204
 
 
2205
  if (!empty($form_state['values']['name']) && is_array($form_state['values']['name'])) {
 
2206
    // Loop through each of the items that were checked and add them to the view.
 
2207
    foreach (array_keys(array_filter($form_state['values']['name'])) as $field) {
 
2208
      list($table, $field) = explode('.', $field, 2);
 
2209
      $id = $form_state['view']->add_item($form_state['display_id'], $type, $table, $field);
 
2210
 
 
2211
      // check to see if this type has settings, if so add the settings form first
 
2212
      $handler = views_get_handler($table, $field, $type);
 
2213
      if ($handler && $handler->has_extra_options()) {
 
2214
        views_ui_add_form_to_stack('config-item-extra', $form_state['view'], $form_state['display_id'], array($type, $id));
 
2215
      }
 
2216
      // Then add the form to the stack
 
2217
      views_ui_add_form_to_stack('config-item', $form_state['view'], $form_state['display_id'], array($type, $id));
 
2218
    }
 
2219
  }
 
2220
 
 
2221
  // Store in cache
 
2222
  views_ui_cache_set($form_state['view']);
 
2223
}
 
2224
 
 
2225
 
 
2226
/**
 
2227
 * Form to config_item items in the views UI.
 
2228
 */
 
2229
function views_ui_config_item_form(&$form_state) {
 
2230
  $view = &$form_state['view'];
 
2231
  $display_id = $form_state['display_id'];
 
2232
  $type = $form_state['type'];
 
2233
  $id = $form_state['id'];
 
2234
 
 
2235
  $form = array('options' => array('#tree' => TRUE));
 
2236
  if (!$view->set_display($display_id)) {
 
2237
    views_ajax_render(t('Invalid display id @display', array('@display' => $display_id)));
 
2238
  }
 
2239
  $item = $view->get_item($display_id, $type, $id);
 
2240
 
 
2241
  if ($item) {
 
2242
    $handler = views_get_handler($item['table'], $item['field'], $type);
 
2243
    if (empty($handler)) {
 
2244
      $form['markup'] = array('#value' => t("Error: handler for @table > @field doesn't exist!", array('@table' => $item['table'], '@field' => $item['field'])));
 
2245
    }
 
2246
    else {
 
2247
      $handler->init($view, $item);
 
2248
      $types = views_object_types();
 
2249
 
 
2250
      if ($view->display_handler->defaultable_sections($types[$type]['plural'])) {
 
2251
        $form_state['section'] = $types[$type]['plural'];
 
2252
        $view->display_handler->add_override_button($form['options'], $form_state, $form_state['section']);
 
2253
      }
 
2254
 
 
2255
      // A whole bunch of code to figure out what relationships are valid for
 
2256
      // this item.
 
2257
      $relationships = $view->display_handler->get_option('relationships');
 
2258
      $relationship_options = array();
 
2259
 
 
2260
      foreach ($relationships as $relationship) {
 
2261
        // relationships can't link back to self. But also, due to ordering,
 
2262
        // relationships can only link to prior relationships.
 
2263
        if ($type == 'relationship' && $id == $relationship['id']) {
 
2264
          break;
 
2265
        }
 
2266
        $relationship_handler = views_get_handler($relationship['table'], $relationship['field'], 'relationship');
 
2267
        // ignore invalid/broken relationships.
 
2268
        if (empty($relationship_handler)) {
 
2269
          continue;
 
2270
        }
 
2271
 
 
2272
        // If this relationship is valid for this type, add it to the list.
 
2273
        $data = views_fetch_data($relationship['table']);
 
2274
        $base = $data[$relationship['field']]['relationship']['base'];
 
2275
        $base_fields = views_fetch_fields($base, $form_state['type']);
 
2276
        if (isset($base_fields[$item['table'] . '.' . $item['field']])) {
 
2277
          $relationship_handler->init($view, $relationship);
 
2278
          $relationship_options[$relationship['id']] = $relationship_handler->label();
 
2279
        }
 
2280
      }
 
2281
 
 
2282
      if (!empty($relationship_options)) {
 
2283
        // Make sure the existing relationship is even valid. If not, force
 
2284
        // it to none.
 
2285
        $base_fields = views_fetch_fields($view->base_table, $form_state['type']);
 
2286
        if (isset($base_fields[$item['table'] . '.' . $item['field']])) {
 
2287
          $relationship_options = array_merge(array('none' => t('Do not use a relationship')), $relationship_options);
 
2288
        }
 
2289
        $rel = empty($item['relationship']) ? 'none' : $item['relationship'];
 
2290
        if (empty($relationship_options[$rel])) {
 
2291
          // Pick the first relationship.
 
2292
          $rel = key($relationship_options);
 
2293
          // We want this relationship option to get saved even if the user
 
2294
          // skips submitting the form.
 
2295
          $view->set_item_option($display_id, $type, $id, 'relationship', $rel);
 
2296
          $temp_view = $view->clone_view();
 
2297
          views_ui_cache_set($temp_view);
 
2298
        }
 
2299
 
 
2300
        $form['options']['relationship'] = array(
 
2301
          '#type' => 'select',
 
2302
          '#title' => t('Relationship'),
 
2303
          '#options' => $relationship_options,
 
2304
          '#default_value' => $rel,
 
2305
        );
 
2306
      }
 
2307
      else {
 
2308
        $form['options']['relationship'] = array(
 
2309
          '#type' => 'value',
 
2310
          '#value' => 'none',
 
2311
        );
 
2312
      }
 
2313
 
 
2314
      $form['#title'] = check_plain($view->display[$display_id]->display_title) . ': ';
 
2315
      $form['#title'] .= t('Configure @type %item', array('@type' => $types[$type]['lstitle'], '%item' => $handler->ui_name()));
 
2316
 
 
2317
      $form['#section'] = $display_id . '-' . $type . '-' . $id;
 
2318
 
 
2319
      // Get form from the handler.
 
2320
      $handler->options_form($form['options'], $form_state);
 
2321
      $form_state['handler'] = &$handler;
 
2322
    }
 
2323
 
 
2324
    $name = NULL;
 
2325
    if (isset($form_state['update_name'])) {
 
2326
      $name = $form_state['update_name'];
 
2327
    }
 
2328
 
 
2329
    views_ui_standard_form_buttons($form, $form_state, 'views_ui_config_item_form', $name, t('Remove'), 'remove');
 
2330
  }
 
2331
  return $form;
 
2332
}
 
2333
 
 
2334
/**
 
2335
 * Submit handler for configing new item(s) to a view.
 
2336
 */
 
2337
function views_ui_config_item_form_validate($form, &$form_state) {
 
2338
  $form_state['handler']->options_validate($form['options'], $form_state);
 
2339
}
 
2340
 
 
2341
/**
 
2342
 * Submit handler for configing new item(s) to a view.
 
2343
 */
 
2344
function views_ui_config_item_form_submit($form, &$form_state) {
 
2345
  // Run it through the handler's submit function.
 
2346
  $form_state['handler']->options_submit($form['options'], $form_state);
 
2347
  $item = $form_state['handler']->options;
 
2348
 
 
2349
  // Unset a button
 
2350
  unset($form_state['values']['options']['expose_button']);
 
2351
 
 
2352
  // Store the data we're given.
 
2353
  foreach ($form_state['values']['options'] as $key => $value) {
 
2354
    $item[$key] = $value;
 
2355
  }
 
2356
 
 
2357
  // Store the item back on the view
 
2358
  $form_state['view']->set_item($form_state['display_id'], $form_state['type'], $form_state['id'], $item);
 
2359
 
 
2360
  $handler = views_get_handler($item['table'], $item['field'], $form_state['type']);
 
2361
  $handler->init($form_state['view'], $item);
 
2362
  if ($handler && $handler->needs_style_plugin()) {
 
2363
    views_ui_add_form_to_stack('change-style', $form_state['view'], $form_state['display_id'], array($form_state['type'], $form_state['id']), TRUE);
 
2364
  }
 
2365
 
 
2366
  // Write to cache
 
2367
  views_ui_cache_set($form_state['view']);
 
2368
}
 
2369
 
 
2370
/**
 
2371
 * Submit handler for removing an item from a view
 
2372
 */
 
2373
function views_ui_config_item_form_remove($form, &$form_state) {
 
2374
  // Store the item back on the view
 
2375
  $form_state['view']->set_item($form_state['display_id'], $form_state['type'], $form_state['id'], NULL);
 
2376
 
 
2377
  // Write to cache
 
2378
  views_ui_cache_set($form_state['view']);
 
2379
}
 
2380
 
 
2381
/**
 
2382
 * Override handler for views_ui_edit_display_form
 
2383
 */
 
2384
function views_ui_config_item_form_expose($form, &$form_state) {
 
2385
  $item = &$form_state['handler']->options;
 
2386
  // flip
 
2387
  $item['exposed'] = empty($item['exposed']);
 
2388
 
 
2389
  // If necessary, set new defaults:
 
2390
  if ($item['exposed']) {
 
2391
    $form_state['handler']->expose_options();
 
2392
  }
 
2393
 
 
2394
  $form_state['view']->set_item($form_state['display_id'], $form_state['type'], $form_state['id'], $item);
 
2395
 
 
2396
  views_ui_cache_set($form_state['view']);
 
2397
  $form_state['rerender'] = TRUE;
 
2398
  $form_state['rebuild'] = TRUE;
 
2399
  $form_state['force_expose_options'] = TRUE;
 
2400
}
 
2401
 
 
2402
/**
 
2403
 * Form to config_item items in the views UI.
 
2404
 */
 
2405
function views_ui_config_item_extra_form(&$form_state) {
 
2406
  $view = &$form_state['view'];
 
2407
  $display_id = $form_state['display_id'];
 
2408
  $type = $form_state['type'];
 
2409
  $id = $form_state['id'];
 
2410
 
 
2411
  $form = array('options' => array('#tree' => TRUE));
 
2412
  if (!$view->set_display($display_id)) {
 
2413
    views_ajax_render(t('Invalid display id @display', array('@display' => $display_id)));
 
2414
  }
 
2415
  $item = $view->get_item($display_id, $type, $id);
 
2416
 
 
2417
  if ($item) {
 
2418
    $handler = views_get_handler($item['table'], $item['field'], $type);
 
2419
    if (empty($handler)) {
 
2420
      $form['markup'] = array('#value' => t("Error: handler for @table > @field doesn't exist!", array('@table' => $item['table'], '@field' => $item['field'])));
 
2421
      break;
 
2422
    }
 
2423
    else {
 
2424
      $handler->init($view, $item);
 
2425
      $types = views_object_types();
 
2426
 
 
2427
      $form['#title'] = check_plain($view->display[$display_id]->display_title) . ': ';
 
2428
      $form['#title'] .= t('Configure extra settings for @type %item', array('@type' => $types[$type]['lstitle'], '%item' => $handler->ui_name()));
 
2429
 
 
2430
      $form['#section'] = $display_id . '-' . $type . '-' . $id;
 
2431
 
 
2432
      // Get form from the handler.
 
2433
      $handler->extra_options_form($form['options'], $form_state);
 
2434
        $form_state['handler'] = &$handler;
 
2435
 
 
2436
    }
 
2437
 
 
2438
    views_ui_standard_form_buttons($form, $form_state, 'views_ui_config_item_extra_form');
 
2439
  }
 
2440
  return $form;
 
2441
}
 
2442
 
 
2443
/**
 
2444
 * Submit handler for configing new item(s) to a view.
 
2445
 */
 
2446
function views_ui_config_item_extra_form_validate($form, &$form_state) {
 
2447
  $form_state['handler']->extra_options_validate($form['options'], $form_state);
 
2448
}
 
2449
 
 
2450
/**
 
2451
 * Submit handler for configing new item(s) to a view.
 
2452
 */
 
2453
function views_ui_config_item_extra_form_submit($form, &$form_state) {
 
2454
  // Run it through the handler's submit function.
 
2455
  $form_state['handler']->extra_options_submit($form['options'], $form_state);
 
2456
  $item = $form_state['handler']->options;
 
2457
 
 
2458
  // Store the data we're given.
 
2459
  foreach ($form_state['values']['options'] as $key => $value) {
 
2460
    $item[$key] = $value;
 
2461
  }
 
2462
 
 
2463
  // Store the item back on the view
 
2464
  $form_state['view']->set_item($form_state['display_id'], $form_state['type'], $form_state['id'], $item);
 
2465
 
 
2466
  // Write to cache
 
2467
  views_ui_cache_set($form_state['view']);
 
2468
}
 
2469
 
 
2470
/**
 
2471
 * Form to change_style items in the views UI.
 
2472
 */
 
2473
function views_ui_change_style_form(&$form_state) {
 
2474
  $view = &$form_state['view'];
 
2475
  $display_id = $form_state['display_id'];
 
2476
  $type = $form_state['type'];
 
2477
  $id = $form_state['id'];
 
2478
 
 
2479
  $form = array('options' => array('#tree' => TRUE));
 
2480
  if (!$view->set_display($display_id)) {
 
2481
    views_ajax_render(t('Invalid display id @display', array('@display' => $display_id)));
 
2482
  }
 
2483
  $item = $view->get_item($display_id, $type, $id);
 
2484
 
 
2485
  if ($item) {
 
2486
    $handler = views_get_handler($item['table'], $item['field'], $type);
 
2487
    if (empty($handler)) {
 
2488
      $form['markup'] = array('#value' => t("Error: handler for @table > @field doesn't exist!", array('@table' => $item['table'], '@field' => $item['field'])));
 
2489
      break;
 
2490
    }
 
2491
    $handler->init($view, $item);
 
2492
    $types = views_object_types();
 
2493
    $form['#title'] = t('Change summary style for @type %item', array('@type' => $types[$type]['lstitle'], '%item' => $handler->ui_name()));
 
2494
 
 
2495
    $form['#section'] = $display_id . '-' . $type . '-' . $id . '-style-plugin';
 
2496
 
 
2497
    $form['style_plugin'] =  array(
 
2498
      '#type' => 'radios',
 
2499
      '#options' => views_fetch_plugin_names('style', 'summary'),
 
2500
      '#default_value' => $item['style_plugin'],
 
2501
    );
 
2502
 
 
2503
    $form_state['handler'] = &$handler;
 
2504
 
 
2505
    views_ui_standard_form_buttons($form, $form_state, 'views_ui_change_style_form');
 
2506
  }
 
2507
  return $form;
 
2508
}
 
2509
 
 
2510
function views_ui_change_style_form_validate($form, &$form_state) {
 
2511
  // Run it through the handler's submit function.
 
2512
  $form_state['handler']->options_validate($form['options'], $form_state);
 
2513
 
 
2514
  $plugin = views_get_plugin('style', $form_state['values']['style_plugin']);
 
2515
  if (!$plugin) {
 
2516
    form_error($form['style_plugin'], t('Internal error: broken plugin.'));
 
2517
  }
 
2518
}
 
2519
 
 
2520
/**
 
2521
 * Submit handler for configing new item(s) to a view.
 
2522
 */
 
2523
function views_ui_change_style_form_submit($form, &$form_state) {
 
2524
  // Run it through the handler's submit function.
 
2525
  $form_state['handler']->options_submit($form['options'], $form_state);
 
2526
  $item = $form_state['handler']->options;
 
2527
 
 
2528
  $plugin = views_get_plugin('style', $form_state['values']['style_plugin']);
 
2529
  if (!$plugin) {
 
2530
    drupal_set_message(t('Internal error: broken plugin.'), 'error');
 
2531
    return;
 
2532
  }
 
2533
 
 
2534
  $plugin->init($form_state['view'], $form_state['view']->display[$form_state['display_id']]);
 
2535
 
 
2536
  // If changing style plugin, reset options to defaults.
 
2537
  if (empty($item['style_plugin']) || $item['style_plugin'] != $form_state['values']['style_plugin']) {
 
2538
    $item['style_options'] = $plugin->options;
 
2539
  }
 
2540
 
 
2541
  // Store the data we're given.
 
2542
  $item['style_plugin'] = $form_state['values']['style_plugin'];
 
2543
 
 
2544
  // Store the item back on the view
 
2545
  $form_state['view']->set_item($form_state['display_id'], $form_state['type'], $form_state['id'], $item);
 
2546
 
 
2547
  if (!empty($plugin->definition['uses options'])) {
 
2548
    views_ui_add_form_to_stack('config-style', $form_state['view'], $form_state['display_id'], array($form_state['type'], $form_state['id']), TRUE);
 
2549
  }
 
2550
 
 
2551
  // Write to cache
 
2552
  views_ui_cache_set($form_state['view']);
 
2553
}
 
2554
 
 
2555
/**
 
2556
 * Form to config_style items in the views UI.
 
2557
 */
 
2558
function views_ui_config_style_form(&$form_state) {
 
2559
  $view = &$form_state['view'];
 
2560
  $display_id = $form_state['display_id'];
 
2561
  $type = $form_state['type'];
 
2562
  $id = $form_state['id'];
 
2563
 
 
2564
  $form = array('options' => array('#tree' => TRUE));
 
2565
  if (!$view->set_display($display_id)) {
 
2566
    views_ajax_render(t('Invalid display id @display', array('@display' => $display_id)));
 
2567
  }
 
2568
  $item = $view->get_item($display_id, $type, $id);
 
2569
 
 
2570
  if ($item) {
 
2571
    $handler = views_get_handler($item['table'], $item['field'], $type);
 
2572
    if (empty($handler)) {
 
2573
      $form['markup'] = array('#value' => t("Error: handler for @table > @field doesn't exist!", array('@table' => $item['table'], '@field' => $item['field'])));
 
2574
      break;
 
2575
    }
 
2576
    $handler->init($view, $item);
 
2577
    $types = views_object_types();
 
2578
 
 
2579
    $form['#title'] = check_plain($view->display[$display_id]->display_title) . ': ';
 
2580
    $form['#title'] .= t('Configure summary style for @type %item', array('@type' => $types[$type]['lstitle'], '%item' => $handler->ui_name()));
 
2581
 
 
2582
    $form['#section'] = $display_id . '-' . $type . '-style-options';
 
2583
 
 
2584
    $plugin = views_get_plugin('style', $item['style_plugin']);
 
2585
    if ($plugin) {
 
2586
      $form['style_options'] = array(
 
2587
        '#tree' => TRUE,
 
2588
      );
 
2589
      $plugin->init($view, $view->display[$display_id], $item['style_options']);
 
2590
 
 
2591
      $plugin->options_form($form['style_options'], $form_state);
 
2592
    }
 
2593
 
 
2594
    $form_state['handler'] = &$handler;
 
2595
 
 
2596
    views_ui_standard_form_buttons($form, $form_state, 'views_ui_config_style_form');
 
2597
  }
 
2598
  return $form;
 
2599
}
 
2600
 
 
2601
/**
 
2602
 * Submit handler for configing new item(s) to a view.
 
2603
 */
 
2604
function views_ui_config_style_form_submit($form, &$form_state) {
 
2605
  // Run it through the handler's submit function.
 
2606
  $form_state['handler']->options_submit($form['style_options'], $form_state);
 
2607
  $item = $form_state['handler']->options;
 
2608
 
 
2609
  // Store the data we're given.
 
2610
  $item['style_options'] = $form_state['values']['style_options'];
 
2611
 
 
2612
  // Store the item back on the view
 
2613
  $form_state['view']->set_item($form_state['display_id'], $form_state['type'], $form_state['id'], $item);
 
2614
 
 
2615
  // Write to cache
 
2616
  views_ui_cache_set($form_state['view']);
 
2617
}
 
2618
 
 
2619
/**
 
2620
 * Get a list of roles in the system.
 
2621
 */
 
2622
function views_ui_get_roles() {
 
2623
  static $roles = NULL;
 
2624
  if (!isset($roles)) {
 
2625
    $roles = array();
 
2626
    $result = db_query("SELECT r.rid, r.name FROM {role} r ORDER BY r.name");
 
2627
    while ($obj = db_fetch_object($result)) {
 
2628
      $roles[$obj->rid] = $obj->name;
 
2629
    }
 
2630
  }
 
2631
 
 
2632
  return $roles;
 
2633
}
 
2634
 
 
2635
/**
 
2636
 * Get a css safe id for a particular section.
 
2637
 */
 
2638
function views_ui_item_css($item) {
 
2639
  return views_css_safe('views-item-' . $item);
 
2640
}
 
2641
 
 
2642
/**
 
2643
 * Page callback for the Views enable page.
 
2644
 */
 
2645
function views_ui_enable_page($view) {
 
2646
  $views_status = variable_get('views_defaults', array());
 
2647
  $views_status[$view->name] = FALSE; // false is enabled
 
2648
  variable_set('views_defaults', $views_status);
 
2649
  views_invalidate_cache();
 
2650
  menu_rebuild();
 
2651
  drupal_goto('admin/build/views');
 
2652
}
 
2653
 
 
2654
/**
 
2655
 * Page callback for the Views enable page
 
2656
 */
 
2657
function views_ui_disable_page($view) {
 
2658
  $views_status = variable_get('views_defaults', array());
 
2659
  $views_status[$view->name] = TRUE; // True is disabled
 
2660
  variable_set('views_defaults', $views_status);
 
2661
  views_invalidate_cache();
 
2662
  menu_rebuild();
 
2663
  drupal_goto('admin/build/views');
 
2664
}
 
2665
 
 
2666
/**
 
2667
 * Page callback for the tools - other page
 
2668
 */
 
2669
function views_ui_admin_tools() {
 
2670
  $form['clear_cache'] = array(
 
2671
    '#type' => 'submit',
 
2672
    '#value' => t("Clear Views' cache"),
 
2673
    '#submit' => array('views_ui_tools_clear_cache'),
 
2674
  );
 
2675
 
 
2676
  $form['views_sql_signature'] = array(
 
2677
    '#type' => 'checkbox',
 
2678
    '#title' => t('Add Views signature to all SQL queries'),
 
2679
    '#description' => t("All Views-generated queries will include a special 'VIEWS' = 'VIEWS' string in the WHERE clause. This makes identifying Views queries in database server logs simpler, but should only be used when troubleshooting."),
 
2680
    '#default_value' => variable_get('views_sql_signature', FALSE),
 
2681
  );
 
2682
 
 
2683
  $form['views_skip_cache'] = array(
 
2684
    '#type' => 'checkbox',
 
2685
    '#title' => t('Disable views data caching'),
 
2686
    '#description' => t("Views caches data about tables, modules and views available, to increase performance. By checking this box, Views will skip this cache and always rebuild this data when needed. This can have a serious performance impact on your site."),
 
2687
    '#default_value' => variable_get('views_skip_cache', FALSE),
 
2688
  );
 
2689
 
 
2690
  $form['views_hide_help_message'] = array(
 
2691
    '#type' => 'checkbox',
 
2692
    '#title' => t('Ignore missing advanced help module'),
 
2693
    '#description' => t("Views uses the advanced help module to provide help text; if this module is not present Views will complain, unless this setting is checked."),
 
2694
    '#default_value' => variable_get('views_hide_help_message', FALSE),
 
2695
  );
 
2696
 
 
2697
  $form['views_ui_query_on_top'] = array(
 
2698
    '#type' => 'checkbox',
 
2699
    '#title' => t('Show query above live preview'),
 
2700
    '#description' => t("The live preview feature will show you the output of the view you're creating, as well as the view. Check here to show the query and other information above the view; leave this unchecked to show that information below the view."),
 
2701
    '#default_value' => variable_get('views_ui_query_on_top', FALSE),
 
2702
  );
 
2703
 
 
2704
  $form['views_show_additional_queries'] = array(
 
2705
    '#type' => 'checkbox',
 
2706
    '#title' => t('Show other queries run during render during live preview'),
 
2707
    '#description' => t("Drupal has the potential to run many queries while a view is being rendered. Checking this box will display every query run during view render as part of the live preview."),
 
2708
    '#default_value' => variable_get('views_show_additional_queries', FALSE),
 
2709
  );
 
2710
 
 
2711
  $form['views_no_hover_links'] = array(
 
2712
    '#type' => 'checkbox',
 
2713
    '#title' => t('Do not show hover links over views'),
 
2714
    '#description' => t("To make it easier to administrate your views, Views provides 'hover' links to take you to the edit and export screen of a view whenever the view is used. This can be distracting on some themes, though; if it is problematic, you can turn it off here."),
 
2715
    '#default_value' => variable_get('views_no_hover_links', FALSE),
 
2716
  );
 
2717
 
 
2718
  $form['views_devel_output'] = array(
 
2719
    '#type' => 'checkbox',
 
2720
    '#title' => t('Enable views performance statistics via the Devel module'),
 
2721
    '#description' => t("Check this to enable some Views query and performance statistics <em>if Devel is installed</em>."),
 
2722
    '#default_value' => variable_get('views_devel_output', FALSE),
 
2723
  );
 
2724
 
 
2725
  $form['views_no_javascript'] = array(
 
2726
    '#type' => 'checkbox',
 
2727
    '#title' => t('Disable javascript with Views'),
 
2728
    '#description' => t("If you are having problems with the javascript, you can disable it here; the Views UI should degrade and still be usable without javascript, it just not as good."),
 
2729
    '#default_value' => variable_get('views_no_javascript', FALSE),
 
2730
  );
 
2731
 
 
2732
  $regions = system_region_list(variable_get('theme_default', 'garland'));
 
2733
 
 
2734
  $form['views_devel_region'] = array(
 
2735
    '#type' => 'select',
 
2736
    '#title' => t('Page region to output performance statistics'),
 
2737
    '#default_value' => variable_get('views_devel_region', 'footer'),
 
2738
    '#options' => $regions,
 
2739
  );
 
2740
 
 
2741
  $form['views_exposed_filter_any_label'] = array(
 
2742
    '#type' => 'select',
 
2743
    '#title' => t('Label for "Any" value on optional single-select exposed filters'),
 
2744
    '#options' => array('old_any' => t('<Any>'), 'new_any' => t('- Any -')),
 
2745
    '#default_value' => variable_get('views_exposed_filter_any_label', 'old_any'),
 
2746
  );
 
2747
 
 
2748
  return system_settings_form($form);
 
2749
}
 
2750
 
 
2751
/**
 
2752
 * Submit hook to clear the views cache.
 
2753
 */
 
2754
function views_ui_tools_clear_cache() {
 
2755
  views_invalidate_cache();
 
2756
  drupal_set_message(t('The cache has been cleared.'));
 
2757
}
 
2758
 
 
2759
/**
 
2760
 * Submit hook to clear Drupal's theme registry (thereby triggering
 
2761
 * a templates rescan).
 
2762
 */
 
2763
function views_ui_config_item_form_rescan($form, &$form_state) {
 
2764
  // Clear *all* theme registry entries:
 
2765
  cache_clear_all('theme_registry:', 'cache', TRUE);
 
2766
  drupal_rebuild_theme_registry();
 
2767
 
 
2768
  // The 'Theme: Information' page is about to be shown again. That page
 
2769
  // analyzes the output of theme_get_registry(). However, this latter
 
2770
  // function uses an internal cache (which was initialized before we
 
2771
  // called drupal_rebuild_theme_registry()) so it won't reflect the
 
2772
  // current state of our theme registry. The only way to clear that cache
 
2773
  // is to re-initialize the theme system:
 
2774
  unset($GLOBALS['theme']);
 
2775
  init_theme();
 
2776
 
 
2777
  $form_state['rerender'] = TRUE;
 
2778
  $form_state['rebuild'] = TRUE;
 
2779
}
 
2780
 
 
2781
/**
 
2782
 * Page callback for views tag autocomplete
 
2783
 */
 
2784
function views_ui_autocomplete_tag($string = '') {
 
2785
  $matches = array();
 
2786
  // get matches from default views:
 
2787
  views_include('view');
 
2788
  $views = views_discover_default_views();
 
2789
  foreach ($views as $view) {
 
2790
    if (!empty($view->tag) && strpos($view->tag, $string) === 0) {
 
2791
      $matches[$view->tag] = $view->tag;
 
2792
    }
 
2793
  }
 
2794
 
 
2795
  if ($string) {
 
2796
    $result = db_query_range("SELECT DISTINCT tag FROM {views_view} WHERE LOWER(tag) LIKE LOWER('%s%%')", $string, 0, 10 - count($matches));
 
2797
    while ($view = db_fetch_object($result)) {
 
2798
      $matches[$view->tag] = check_plain($view->tag);
 
2799
    }
 
2800
  }
 
2801
 
 
2802
  drupal_json($matches);
 
2803
}
 
2804
 
 
2805
// ------------------------------------------------------------------
 
2806
// Get information from the Views data
 
2807
 
 
2808
function _views_weight_sort($a, $b) {
 
2809
  if ($a['weight'] != $b['weight']) {
 
2810
    return $a['weight'] < $b['weight'] ? -1 : 1;
 
2811
  }
 
2812
  if ($a['title'] != $b['title']) {
 
2813
    return $a['title'] < $b['title'] ? -1 : 1;
 
2814
  }
 
2815
 
 
2816
  return 0;
 
2817
}
 
2818
 
 
2819
/**
 
2820
 * Fetch a list of all base tables available
 
2821
 *
 
2822
 * @return
 
2823
 *   A keyed array of in the form of 'base_table' => 'Description'.
 
2824
 */
 
2825
function views_fetch_base_tables() {
 
2826
  static $base_tables = array();
 
2827
  if (empty($base_tables)) {
 
2828
    $weights = array();
 
2829
    $tables = array();
 
2830
    $data = views_fetch_data();
 
2831
    foreach ($data as $table => $info) {
 
2832
      if (!empty($info['table']['base'])) {
 
2833
        $tables[$table] = array(
 
2834
          'title' => $info['table']['base']['title'],
 
2835
          'description' => $info['table']['base']['help'],
 
2836
          'weight' => !empty($info['table']['base']['weight']) ? $info['table']['base']['weight'] : 0,
 
2837
        );
 
2838
      }
 
2839
    }
 
2840
    uasort($tables, '_views_weight_sort');
 
2841
    $base_tables = $tables;
 
2842
  }
 
2843
 
 
2844
  return $base_tables;
 
2845
}
 
2846
 
 
2847
function _views_sort_types($a, $b) {
 
2848
  if ($a['group'] != $b['group']) {
 
2849
    return $a['group'] < $b['group'] ? -1 : 1;
 
2850
  }
 
2851
 
 
2852
  if ($a['title'] != $b['title']) {
 
2853
    return $a['title'] < $b['title'] ? -1 : 1;
 
2854
  }
 
2855
 
 
2856
  return 0;
 
2857
}
 
2858
 
 
2859
/**
 
2860
 * Fetch a list of all fields available for a given base type.
 
2861
 *
 
2862
 * @return
 
2863
 *   A keyed array of in the form of 'base_table' => 'Description'.
 
2864
 */
 
2865
function views_fetch_fields($base, $type) {
 
2866
  static $fields = array();
 
2867
  if (empty($fields)) {
 
2868
    $data = views_fetch_data();
 
2869
    $start = views_microtime();
 
2870
    // This constructs this ginormous multi dimensional array to
 
2871
    // collect the important data about fields. In the end,
 
2872
    // the structure looks a bit like this (using nid as an example)
 
2873
    // $strings['nid']['filter']['title'] = 'string'.
 
2874
    //
 
2875
    // This is constructed this way because the above referenced strings
 
2876
    // can appear in different places in the actual data structure so that
 
2877
    // the data doesn't have to be repeated a lot. This essentially lets
 
2878
    // each field have a cheap kind of inheritance.
 
2879
 
 
2880
    foreach ($data as $table => $table_data) {
 
2881
      $bases = array();
 
2882
      $strings = array();
 
2883
      $skip_bases = array();
 
2884
      foreach ($table_data as $field => $info) {
 
2885
        // Collect table data from this table
 
2886
        if ($field == 'table') {
 
2887
          // calculate what tables this table can join to.
 
2888
          if (!empty($info['join'])) {
 
2889
            $bases = array_keys($info['join']);
 
2890
          }
 
2891
          // And it obviously joins to itself.
 
2892
          $bases[] = $table;
 
2893
          continue;
 
2894
        }
 
2895
        foreach (array('field', 'sort', 'filter', 'argument', 'relationship') as $key) {
 
2896
          if (!empty($info[$key])) {
 
2897
            if (!empty($info[$key]['skip base'])) {
 
2898
              foreach ((array) $info[$key]['skip base'] as $base_name) {
 
2899
                $skip_bases[$field][$key][$base_name] = TRUE;
 
2900
              }
 
2901
            }
 
2902
            elseif (!empty($info['skip base'])) {
 
2903
              foreach ((array) $info['skip base'] as $base_name) {
 
2904
                $skip_bases[$field][$key][$base_name] = TRUE;
 
2905
              }
 
2906
            }
 
2907
            foreach (array('title', 'group', 'help', 'base') as $string) {
 
2908
              // First, try the lowest possible level
 
2909
              if (!empty($info[$key][$string])) {
 
2910
                $strings[$field][$key][$string] = $info[$key][$string];
 
2911
              }
 
2912
              // Then try the field level
 
2913
              elseif (!empty($info[$string])) {
 
2914
                $strings[$field][$key][$string] = $info[$string];
 
2915
              }
 
2916
              // Finally, try the table level
 
2917
              elseif (!empty($table_data['table'][$string])) {
 
2918
                $strings[$field][$key][$string] = $table_data['table'][$string];
 
2919
              }
 
2920
              else {
 
2921
                if ($string != 'base') {
 
2922
                  $strings[$field][$key][$string] = t("Error: missing @component", array('@component' => $string));
 
2923
                }
 
2924
              }
 
2925
            }
 
2926
          }
 
2927
        }
 
2928
      }
 
2929
      foreach ($bases as $base_name) {
 
2930
        foreach ($strings as $field => $field_strings) {
 
2931
          foreach ($field_strings as $type_name => $type_strings) {
 
2932
            if (empty($skip_bases[$field][$type_name][$base_name])) {
 
2933
              $fields[$base_name][$type_name]["$table.$field"] = $type_strings;
 
2934
            }
 
2935
          }
 
2936
        }
 
2937
      }
 
2938
    }
 
2939
//    vsm('Views UI data build time: ' . (views_microtime() - $start) * 1000 . ' ms');
 
2940
  }
 
2941
 
 
2942
  // If we have an array of base tables available, go through them
 
2943
  // all and add them together. Duplicate keys will be lost and that's
 
2944
  // Just Fine.
 
2945
  if (is_array($base)) {
 
2946
    $strings = array();
 
2947
    foreach ($base as $base_table) {
 
2948
      if (isset($fields[$base_table][$type])) {
 
2949
        $strings += $fields[$base_table][$type];
 
2950
      }
 
2951
    }
 
2952
    uasort($strings, '_views_sort_types');
 
2953
    return $strings;
 
2954
  }
 
2955
 
 
2956
  if (isset($fields[$base][$type])) {
 
2957
    uasort($fields[$base][$type], '_views_sort_types');
 
2958
    return $fields[$base][$type];
 
2959
  }
 
2960
  return array();
 
2961
}
 
2962
 
 
2963
/**
 
2964
 * Fetch a list of all base tables available
 
2965
 *
 
2966
 * @param $type
 
2967
 *   Either 'display', 'style' or 'row'
 
2968
 * @param $key
 
2969
 *   For style plugins, this is an optional type to restrict to. May be 'normal',
 
2970
 *   'summary', 'feed' or others based on the neds of the display.
 
2971
 * @param $base
 
2972
 *   An array of possible base tables.
 
2973
 *
 
2974
 * @return
 
2975
 *   A keyed array of in the form of 'base_table' => 'Description'.
 
2976
 */
 
2977
function views_fetch_plugin_names($type, $key = NULL, $base = array()) {
 
2978
  $data = views_fetch_plugin_data();
 
2979
 
 
2980
  $plugins[$type] = array();
 
2981
 
 
2982
  foreach ($data[$type] as $id => $plugin) {
 
2983
    // Skip plugins that don't conform to our key.
 
2984
    if ($key && (empty($plugin['type']) || $plugin['type'] != $key)) {
 
2985
      continue;
 
2986
    }
 
2987
    if (empty($plugin['no ui']) && (empty($base) || empty($plugin['base']) || array_intersect($base, $plugin['base']))) {
 
2988
      $plugins[$type][$id] = $plugin['title'];
 
2989
    }
 
2990
  }
 
2991
 
 
2992
  if (!empty($plugins[$type])) {
 
2993
    asort($plugins[$type]);
 
2994
    return $plugins[$type];
 
2995
  }
 
2996
  // fall-through
 
2997
  return array();
 
2998
}
 
2999
 
 
3000
 
 
3001
/**
 
3002
 * Theme the form for the table style plugin
 
3003
 */
 
3004
function theme_views_ui_style_plugin_table($form) {
 
3005
  $output = drupal_render($form['description_markup']);
 
3006
 
 
3007
  $header = array(
 
3008
    t('Field'),
 
3009
    t('Column'),
 
3010
    t('Separator'),
 
3011
    array(
 
3012
      'data' => t('Sortable'),
 
3013
      'align' => 'center',
 
3014
    ),
 
3015
    array(
 
3016
      'data' => t('Default sort'),
 
3017
      'align' => 'center',
 
3018
    ),
 
3019
  );
 
3020
  $rows = array();
 
3021
  foreach (element_children($form['columns']) as $id) {
 
3022
    $row = array();
 
3023
    $row[] = drupal_render($form['info'][$id]['name']);
 
3024
    $row[] = drupal_render($form['columns'][$id]);
 
3025
    $row[] = drupal_render($form['info'][$id]['separator']);
 
3026
    if (!empty($form['info'][$id]['sortable'])) {
 
3027
      $row[] = array(
 
3028
        'data' => drupal_render($form['info'][$id]['sortable']),
 
3029
        'align' => 'center',
 
3030
      );
 
3031
      $row[] = array(
 
3032
        'data' => drupal_render($form['default'][$id]),
 
3033
        'align' => 'center',
 
3034
      );
 
3035
    }
 
3036
    else {
 
3037
      $row[] = '';
 
3038
      $row[] = '';
 
3039
    }
 
3040
    $rows[] = $row;
 
3041
  }
 
3042
 
 
3043
  // Add the special 'None' row.
 
3044
  $rows[] = array(t('None'), '', '', '', array('align' => 'center', 'data' => drupal_render($form['default'][-1])));
 
3045
 
 
3046
  $output .= theme('table', $header, $rows);
 
3047
  $output .= drupal_render($form);
 
3048
  return $output;
 
3049
}
 
3050