Project

General

Profile

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

root / drupal7 / sites / all / modules / views / views_ui.module @ 4003efde

1
<?php
2

    
3
/**
4
 * @file
5
 * Provide structure for the administrative interface to Views.
6
 */
7

    
8
/**
9
 * Implements hook_help().
10
 */
11
function views_ui_help($path, $arg) {
12
  switch ($path) {
13
    case 'admin/help#views_ui':
14
      $output = '';
15
      $output .= '<h3>' . t('About') . '</h3>';
16
      $output .= '<p>' . t('The Views UI module provides an interface for managing views for the Views module. For more information, see the <a href="@views" target="blank">online documentation for the Views UI module</a>.', array('@views' => 'https://www.drupal.org/documentation/modules/views')) . '</p>';
17
      $output .= '<h3>' . t('Uses') . '</h3>';
18
      $output .= '<dl>';
19
      $output .= '<dt>' . t('Creating and managing views') . '</dt>';
20
      $output .= '<dd>' . t('Views can be created from the <a href="/admin/structure/views">Views list page</a> by using the "Add view" action. Existing views can be managed from the <a href="/admin/structure/views">Views list page</a> by locating the view in the "Enabled" or "Disabled" list and selecting the desired operation action, for example "Edit".') . '</dd>';
21

    
22
      $output .= '<dt>' . t('Enabling and disabling views') . '</dt>';
23
      $output .= '<dd>' . t('Views can be enabled or disabled from the <a href="/admin/structure/views">Views list page</a>. To enable a view, find the view within the "Disabled" list and select the "Enable" operation. To disable a view find the view within the "Enabled" list and select the "Disable" operation.') . '</dd>';
24

    
25
      $output .= '<dt>' . t('Exporting and importing views') . '</dt>';
26
      $output .= '<dd>' . t('Views can be exported and imported as configuration files by using the Configuration Manager module.') . '</dd>';
27
      return $output;
28
  }
29
}
30

    
31
/**
32
 * Implements hook_menu().
33
 */
34
function views_ui_menu() {
35
  $items = array();
36

    
37
  // Minor code reduction technique.
38
  $base = array(
39
    'access callback' => 'user_access',
40
    'access arguments' => array('administer views'),
41
    'file' => 'includes/admin.inc',
42
  );
43

    
44
  // Top-level Views module pages (not tied to a particular View).
45
  $items['admin/structure/views/add'] = array(
46
    'title' => 'Add new view',
47
    'page callback' => 'views_ui_add_page',
48
    'type' => MENU_LOCAL_ACTION,
49
  ) + $base;
50

    
51
  // Top-level Views module pages (not tied to a particular View).
52
  $items['admin/structure/views/add-template'] = array(
53
    'title' => 'Add view from template',
54
    'page callback' => 'views_ui_add_template_page',
55
    // Don't show a local action link if there aren't any templates.
56
    'type' => views_get_all_templates() ? MENU_LOCAL_ACTION : MENU_VISIBLE_IN_BREADCRUMB,
57
  ) + $base;
58

    
59
  $items['admin/structure/views/import'] = array(
60
    'title' => 'Import',
61
    'page callback' => 'drupal_get_form',
62
    'page arguments' => array('views_ui_import_page'),
63
    'access callback' => 'views_import_access',
64
    'type' => MENU_LOCAL_ACTION,
65
  ) + $base;
66

    
67
  $items['admin/structure/views/settings'] = array(
68
    'title' => 'Settings',
69
    'page callback' => 'drupal_get_form',
70
    'page arguments' => array('views_ui_admin_settings_basic'),
71
    'type' => MENU_LOCAL_TASK,
72
  ) + $base;
73
  $items['admin/structure/views/settings/basic'] = array(
74
    'title' => 'Basic',
75
    'page arguments' => array('views_ui_admin_settings_basic'),
76
    'type' => MENU_DEFAULT_LOCAL_TASK,
77
  ) + $base;
78
  $items['admin/structure/views/settings/advanced'] = array(
79
    'title' => 'Advanced',
80
    'page arguments' => array('views_ui_admin_settings_advanced'),
81
    'type' => MENU_LOCAL_TASK,
82
    'weight' => 1,
83
  ) + $base;
84

    
85
  // The primary Edit View page. Secondary tabs for each Display are added in
86
  // views_ui_menu_local_tasks_alter().
87
  $items['admin/structure/views/view/%views_ui_cache'] = array(
88
    'title callback' => 'views_ui_edit_page_title',
89
    'title arguments' => array(4),
90
    'page callback' => 'views_ui_edit_page',
91
    'page arguments' => array(4),
92
  ) + $base;
93
  $items['admin/structure/views/view/%views_ui_cache/edit'] = array(
94
    'title' => 'Edit view',
95
    'type' => MENU_DEFAULT_LOCAL_TASK,
96
    'context' => MENU_CONTEXT_PAGE | MENU_CONTEXT_INLINE,
97
    'weight' => -10,
98
    'theme callback' => 'ajax_base_page_theme',
99
  ) + $base;
100
  $items['admin/structure/views/view/%views_ui_cache/edit/%/ajax'] = array(
101
    'page callback' => 'views_ui_ajax_get_form',
102
    'page arguments' => array('views_ui_edit_form', 4, 6),
103
    'delivery callback' => 'ajax_deliver',
104
    'theme callback' => 'ajax_base_page_theme',
105
    'type' => MENU_CALLBACK,
106
  ) + $base;
107
  $items['admin/structure/views/view/%views_ui_cache/preview/%'] = array(
108
    'page callback' => 'views_ui_build_preview',
109
    'page arguments' => array(4, 6),
110
    'context' => MENU_CONTEXT_PAGE | MENU_CONTEXT_INLINE,
111
    'type' => MENU_VISIBLE_IN_BREADCRUMB,
112
  ) + $base;
113
  $items['admin/structure/views/view/%views_ui_cache/preview/%/ajax'] = array(
114
    'page callback' => 'views_ui_build_preview',
115
    'page arguments' => array(4, 6),
116
    'delivery callback' => 'ajax_deliver',
117
    'theme callback' => 'ajax_base_page_theme',
118
    'type' => MENU_CALLBACK,
119
  ) + $base;
120

    
121
  // Additional pages for acting on a View.
122
  $items['admin/structure/views/view/%views_ui_cache/break-lock'] = array(
123
    'title' => 'Break lock',
124
    'page callback' => 'drupal_get_form',
125
    'page arguments' => array('views_ui_break_lock_confirm', 4),
126
    'type' => MENU_VISIBLE_IN_BREADCRUMB,
127
  ) + $base;
128

    
129
  // NoJS/AJAX callbacks that can use the default Views AJAX form system.
130
  $items['admin/structure/views/nojs/%/%views_ui_cache'] = array(
131
    'page callback' => 'views_ui_ajax_form',
132
    'page arguments' => array(FALSE, 4, 5),
133
    'type' => MENU_CALLBACK,
134
  ) + $base;
135
  $items['admin/structure/views/ajax/%/%views_ui_cache'] = array(
136
    'page callback' => 'views_ui_ajax_form',
137
    'page arguments' => array(TRUE, 4, 5),
138
    'delivery callback' => 'ajax_deliver',
139
    'type' => MENU_CALLBACK,
140
  ) + $base;
141

    
142
  // NoJS/AJAX callbacks that require custom page callbacks.
143
  $ajax_callbacks = array(
144
    'preview' => 'views_ui_preview',
145
  );
146
  foreach ($ajax_callbacks as $menu => $menu_callback) {
147
    $items['admin/structure/views/nojs/' . $menu . '/%views_ui_cache/%'] = array(
148
      'page callback' => $menu_callback,
149
      'page arguments' => array(5, 6),
150
    ) + $base;
151
    $items['admin/structure/views/ajax/' . $menu . '/%views_ui_cache/%'] = array(
152
      'page callback' => $menu_callback,
153
      'page arguments' => array(5, 6),
154
      'delivery callback' => 'ajax_deliver',
155
    ) + $base;
156
  }
157

    
158
  // Autocomplete callback for tagging a View.
159
  // Views module uses admin/views/... instead of admin/structure/views/... for
160
  // autocomplete paths, so be consistent with that.
161
  // @todo Change to admin/structure/views/... when the change can be made to
162
  //   Views module as well.
163
  $items['admin/views/ajax/autocomplete/tag'] = array(
164
    'page callback' => 'views_ui_autocomplete_tag',
165
    'type' => MENU_CALLBACK,
166
  ) + $base;
167

    
168
  // A page in the Reports section to show usage of fields in all views.
169
  $items['admin/reports/fields/list'] = array(
170
    'title' => 'List',
171
    'type' => MENU_DEFAULT_LOCAL_TASK,
172
    'weight' => -10,
173
  );
174
  $items['admin/reports/fields/views-fields'] = array(
175
    'title' => 'Used in views',
176
    'description' => 'Overview of fields used in all views.',
177
    'page callback' => 'views_ui_field_list',
178
    'type' => MENU_LOCAL_TASK,
179
    'weight' => 0,
180
  ) + $base;
181

    
182
  // A page in the Reports section to show usage of plugins in all views.
183
  $items['admin/reports/views-plugins'] = array(
184
    'title' => 'Views plugins',
185
    'description' => 'Overview of plugins used in all views.',
186
    'page callback' => 'views_ui_plugin_list',
187
  ) + $base;
188

    
189
  return $items;
190
}
191

    
192
/**
193
 * Implements hook_theme().
194
 */
195
function views_ui_theme() {
196
  $path = drupal_get_path('module', 'views');
197
  require_once DRUPAL_ROOT . "/$path/includes/admin.inc";
198

    
199
  return array(
200
    // Edit a view.
201
    'views_ui_display_tab_setting' => array(
202
      'variables' => array(
203
        'description' => '',
204
        'link' => '',
205
        'settings_links' => array(),
206
        'overridden' => FALSE,
207
        'defaulted' => FALSE,
208
        'description_separator' => TRUE,
209
        'class' => array(),
210
      ),
211
      'template' => 'views-ui-display-tab-setting',
212
      'path' => "$path/theme",
213
    ),
214
    'views_ui_display_tab_bucket' => array(
215
      'render element' => 'element',
216
      'template' => 'views-ui-display-tab-bucket',
217
      'path' => "$path/theme",
218
    ),
219
    'views_ui_rearrange_form' => array(
220
      'render element' => 'form',
221
    ),
222
    'views_ui_rearrange_filter_form' => array(
223
      'render element' => 'form',
224
      'file' => 'includes/admin.inc',
225
    ),
226
    'views_ui_expose_filter_form' => array(
227
      'render element' => 'form',
228
      'file' => 'includes/admin.inc',
229
    ),
230

    
231
    // List views.
232
    'views_ui_view_info' => array(
233
      'variables' => array('view' => NULL, 'base' => NULL),
234
      'file' => "includes/admin.inc",
235
    ),
236

    
237
    // Group of filters.
238
    'views_ui_build_group_filter_form' => array(
239
      'render element' => 'form',
240
      'file' => 'includes/admin.inc',
241
    ),
242

    
243
    // Tab themes.
244
    'views_tabset' => array(
245
      'variables' => array('tabs' => NULL),
246
    ),
247
    'views_tab' => array(
248
      'variables' => array('body' => NULL),
249
    ),
250
    'views_ui_reorder_displays_form' => array(
251
      'render element' => 'form',
252
      'file' => 'includes/admin.inc',
253
    ),
254

    
255
    // On behalf of a plugin.
256
    'views_ui_style_plugin_table' => array(
257
      'render element' => 'form',
258
    ),
259

    
260
    // When previewing a view.
261
    'views_ui_view_preview_section' => array(
262
      'variables' => array(
263
        'view' => NULL,
264
        'section' => NULL,
265
        'content' => NULL,
266
        'links' => '',
267
      ),
268
    ),
269

    
270
    // Generic container wrapper, to use instead of theme_container when an id
271
    // is not desired.
272
    'views_container' => array(
273
      'render element' => 'element',
274
      'file' => 'theme/theme.inc',
275
    ),
276
  );
277
}
278

    
279
/**
280
 * Implements hook_custom_theme().
281
 */
282
function views_ui_custom_theme() {
283
  $theme = variable_get('views_ui_custom_theme', '_default');
284

    
285
  if ($theme != '_default') {
286
    $available = list_themes();
287

    
288
    if (isset($available[$theme]) && $available[$theme]->status && preg_match('/^admin\/structure\/views/', current_path())) {
289
      return $theme;
290
    }
291
  }
292
}
293

    
294
/**
295
 * Page title callback for the Edit View page.
296
 */
297
function views_ui_edit_page_title($view) {
298
  module_load_include('inc', 'views_ui', 'includes/admin');
299
  $bases = views_fetch_base_tables();
300
  $name = $view->get_human_name();
301
  if (isset($bases[$view->base_table])) {
302
    $name .= ' (' . $bases[$view->base_table]['title'] . ')';
303
  }
304

    
305
  return $name;
306
}
307

    
308
/**
309
 * Specialized menu callback to load a view and check its locked status.
310
 *
311
 * @param string $name
312
 *   The machine name of the view.
313
 *
314
 * @return object
315
 *   The view object, with a "locked" property indicating whether or not
316
 *   someone else is already editing the view.
317
 */
318
function views_ui_cache_load($name) {
319
  ctools_include('object-cache');
320
  views_include('view');
321
  $view = ctools_object_cache_get('view', $name);
322
  $original_view = views_get_view($name);
323

    
324
  if (empty($view)) {
325
    $view = $original_view;
326
    if (!empty($view)) {
327
      // Check to see if someone else is already editing this view.
328
      $view->locked = ctools_object_cache_test('view', $view->name);
329
      // Set a flag to indicate that this view is being edited.
330
      // This flag will be used e.g. to determine whether strings
331
      // should be localized.
332
      $view->editing = TRUE;
333
    }
334
  }
335
  else {
336
    // Keep disabled/enabled status real.
337
    if ($original_view) {
338
      $view->disabled = !empty($original_view->disabled);
339
    }
340
  }
341

    
342
  if (empty($view)) {
343
    return FALSE;
344
  }
345

    
346
  else {
347
    return $view;
348
  }
349
}
350

    
351
/**
352
 * Cache set.
353
 *
354
 * Specialized cache function to add a flag to our view, include an appropriate
355
 * include, and cache more easily.
356
 */
357
function views_ui_cache_set(&$view) {
358
  if (!empty($view->locked)) {
359
    drupal_set_message(t('Changes cannot be made to a locked view.'), 'error');
360
    return;
361
  }
362
  ctools_include('object-cache');
363
  // Let any future object know that this view has changed.
364
  $view->changed = TRUE;
365

    
366
  if (isset($view->current_display)) {
367
    // Add the knowledge of the changed display, too.
368
    $view->changed_display[$view->current_display] = TRUE;
369
    unset($view->current_display);
370
  }
371

    
372
  // Unset handlers; we don't want to write these into the cache.
373
  unset($view->display_handler);
374
  unset($view->default_display);
375
  $view->query = NULL;
376
  foreach (array_keys($view->display) as $id) {
377
    unset($view->display[$id]->handler);
378
    unset($view->display[$id]->default_display);
379
  }
380
  ctools_object_cache_set('view', $view->name, $view);
381
}
382

    
383
/**
384
 * Default Load.
385
 *
386
 * Specialized menu callback to load a view that is only a default
387
 * view.
388
 */
389
function views_ui_default_load($name) {
390
  $view = views_get_view($name);
391
  if ($view->type == t('Default')) {
392
    return $view;
393
  }
394

    
395
  return FALSE;
396
}
397

    
398
/**
399
 * Theme preprocess for views-view.tpl.php.
400
 */
401
function views_ui_preprocess_views_view(&$vars) {
402
  $view = $vars['view'];
403
  if (!empty($view->views_ui_context) && module_exists('contextual')) {
404
    $view->hide_admin_links = TRUE;
405

    
406
    $sections = array(
407
      'title',
408
      'header',
409
      'exposed',
410
      'rows',
411
      'pager',
412
      'more',
413
      'footer',
414
      'empty',
415
      'attachment_after',
416
      'attachment_before',
417
    );
418

    
419
    foreach ($sections as $section) {
420
      if (!empty($vars[$section])) {
421
        $vars[$section] = array(
422
          '#theme' => 'views_ui_view_preview_section',
423
          '#view' => $view,
424
          '#section' => $section,
425
          '#content' => is_array($vars[$section]) ? drupal_render($vars[$section]) : $vars[$section],
426
          '#theme_wrappers' => array('views_container'),
427
          '#attributes' => array('class' => 'contextual-links-region'),
428
        );
429
        $vars[$section] = drupal_render($vars[$section]);
430
      }
431
    }
432
  }
433
}
434

    
435
/**
436
 * Theme preprocess for theme_views_ui_view_preview_section().
437
 *
438
 * @todo Perhaps move this to includes/admin.inc or theme/theme.inc.
439
 */
440
function template_preprocess_views_ui_view_preview_section(&$vars) {
441
  switch ($vars['section']) {
442
    case 'title':
443
      $vars['title'] = t('Title');
444
      $links = views_ui_view_preview_section_display_category_links($vars['view'], 'title', $vars['title']);
445
      break;
446

    
447
    case 'header':
448
      $vars['title'] = t('Header');
449
      $links = views_ui_view_preview_section_handler_links($vars['view'], $vars['section']);
450
      break;
451

    
452
    case 'empty':
453
      $vars['title'] = t('No results behavior');
454
      $links = views_ui_view_preview_section_handler_links($vars['view'], $vars['section']);
455
      break;
456

    
457
    case 'exposed':
458
      // @todo Sorts can be exposed too, so we may need a better title.
459
      $vars['title'] = t('Exposed Filters');
460
      $links = views_ui_view_preview_section_display_category_links($vars['view'], 'exposed_form_options', $vars['title']);
461
      break;
462

    
463
    case 'rows':
464
      // @todo The title needs to depend on what is being viewed.
465
      $vars['title'] = t('Content');
466
      $links = views_ui_view_preview_section_rows_links($vars['view']);
467
      break;
468

    
469
    case 'pager':
470
      $vars['title'] = t('Pager');
471
      $links = views_ui_view_preview_section_display_category_links($vars['view'], 'pager_options', $vars['title']);
472
      break;
473

    
474
    case 'more':
475
      $vars['title'] = t('More');
476
      $links = views_ui_view_preview_section_display_category_links($vars['view'], 'use_more', $vars['title']);
477
      break;
478

    
479
    case 'footer':
480
      $vars['title'] = t('Footer');
481
      $links = views_ui_view_preview_section_handler_links($vars['view'], $vars['section']);
482
      break;
483

    
484
    case 'attachment_before':
485
      // @todo Add links to the attachment configuration page.
486
      $vars['title'] = t('Attachment before');
487
      break;
488

    
489
    case 'attachment_after':
490
      // @todo Add links to the attachment configuration page.
491
      $vars['title'] = t('Attachment after');
492
      break;
493
  }
494

    
495
  if (isset($links)) {
496
    $build = array(
497
      '#prefix' => '<div class="contextual-links-wrapper">',
498
      '#suffix' => '</div>',
499
      '#theme' => 'links__contextual',
500
      '#links' => $links,
501
      '#attributes' => array('class' => array('contextual-links')),
502
      '#attached' => array(
503
        'library' => array(array('contextual', 'contextual-links')),
504
      ),
505
    );
506
    $vars['links'] = drupal_render($build);
507
  }
508
  $vars['theme_hook_suggestions'][] = 'views_ui_view_preview_section__' . $vars['section'];
509
}
510

    
511
/**
512
 * Returns the HTML for a section of a View being previewed within the Views UI.
513
 */
514
function theme_views_ui_view_preview_section($vars) {
515
  return '<h1 class="section-title">' . $vars['title'] . '</h1>'
516
  . $vars['links']
517
  . '<div class="preview-section">' . $vars['content'] . '</div>';
518
}
519

    
520
/**
521
 * Returns contextual links for each handler of a certain section.
522
 *
523
 * @param string $title
524
 *   Add a bolded title of this section.
525
 *
526
 * @todo Bring in relationships.
527
 * @todo Refactor this function to use much of views_ui_edit_form_get_bucket.
528
 */
529
function views_ui_view_preview_section_handler_links($view, $type, $title = FALSE) {
530
  $display = $view->display_handler->display;
531
  $handlers = $view->display_handler->get_handlers($type);
532
  $links = array();
533

    
534
  $types = views_object_types();
535
  if ($title) {
536
    $links[$type . '-title'] = array(
537
      'title' => $types[$type]['title'],
538
    );
539
  }
540

    
541
  foreach ($handlers as $id => $handler) {
542
    $field_name = $handler->ui_name(TRUE);
543
    $links[$type . '-edit-' . $id] = array(
544
      'title' => t('Edit @section', array('@section' => $field_name)),
545
      'href' => "admin/structure/views/nojs/config-item/$view->name/$display->id/$type/$id",
546
      'attributes' => array('class' => array('views-ajax-link')),
547
    );
548
  }
549
  $links[$type . '-add'] = array(
550
    'title' => t('Add new'),
551
    'href' => "admin/structure/views/nojs/add-item/$view->name/$display->id/$type",
552
    'attributes' => array('class' => array('views-ajax-link')),
553
  );
554

    
555
  return $links;
556
}
557

    
558
/**
559
 * Returns a link to editing a certain display setting.
560
 */
561
function views_ui_view_preview_section_display_category_links($view, $type, $title) {
562
  $display = $view->display_handler->display;
563
  $links = array(
564
    $type . '-edit' => array(
565
      'title' => t('Edit @section', array('@section' => $title)),
566
      'href' => "admin/structure/views/nojs/display/$view->name/$display->id/$type",
567
      'attributes' => array('class' => array('views-ajax-link')),
568
    ),
569
  );
570

    
571
  return $links;
572
}
573

    
574
/**
575
 * Returns all contextual links for the main content part of the view.
576
 */
577
function views_ui_view_preview_section_rows_links($view) {
578

    
579
  $links = array();
580

    
581
  $links = array_merge($links, views_ui_view_preview_section_handler_links($view, 'filter', TRUE));
582
  $links = array_merge($links, views_ui_view_preview_section_handler_links($view, 'field', TRUE));
583
  $links = array_merge($links, views_ui_view_preview_section_handler_links($view, 'sort', TRUE));
584
  $links = array_merge($links, views_ui_view_preview_section_handler_links($view, 'argument', TRUE));
585
  $links = array_merge($links, views_ui_view_preview_section_handler_links($view, 'relationship', TRUE));
586

    
587
  return $links;
588
}
589

    
590
/**
591
 * Implments hook_ctools_plugin_directory().
592
 *
593
 * Views UI provides wizard plugins on behalf of core base tables.
594
 */
595
function views_ui_ctools_plugin_directory($module, $plugin) {
596
  if ($module == 'views_ui' || ($module == 'ctools' && $plugin == 'export_ui')) {
597
    return 'plugins/' . $plugin;
598
  }
599
}
600

    
601
/**
602
 * Fetch metadata on a specific views ui wizard plugin.
603
 *
604
 * @param string $wizard_type
605
 *   Name of a wizard, or name of a base table.
606
 *
607
 * @return array
608
 *   An array with information about the requested wizard type.
609
 */
610
function views_ui_get_wizard($wizard_type) {
611
  ctools_include('plugins');
612
  $wizard = ctools_get_plugins('views_ui', 'views_wizard', $wizard_type);
613
  // @todo - handle this via an alter hook instead.
614
  if (!$wizard) {
615
    // Must be a base table using the default wizard plugin.
616
    $base_tables = views_fetch_base_tables();
617
    if (!empty($base_tables[$wizard_type])) {
618
      $wizard = views_ui_views_wizard_defaults();
619
      $wizard['base_table'] = $wizard_type;
620
      $wizard['title'] = $base_tables[$wizard_type]['title'];
621
    }
622
    // The plugin is neither a base table nor an existing wizard.
623
    else {
624
      vpr('Views Wizard: @wizard does not exist. Be sure to implement hook_ctools_plugin_directory.', array('@wizard' => $wizard_type));
625
    }
626
  }
627
  return $wizard;
628
}
629

    
630
/**
631
 * Fetch metadata for all content_type plugins.
632
 *
633
 * @return array
634
 *   An array of arrays with information about all available views wizards.
635
 */
636
function views_ui_get_wizards() {
637
  ctools_include('plugins');
638
  $wizard_plugins = ctools_get_plugins('views_ui', 'views_wizard');
639
  $wizard_tables = array();
640
  foreach ($wizard_plugins as $info) {
641
    $wizard_tables[$info['base_table']] = TRUE;
642
  }
643
  $base_tables = views_fetch_base_tables();
644
  $default_wizard = views_ui_views_wizard_defaults();
645
  // Find base tables with no wizard.
646
  // @todo - handle this via an alter hook for plugins?
647
  foreach ($base_tables as $table => $info) {
648
    if (!isset($wizard_tables[$table])) {
649
      $wizard = $default_wizard;
650
      $wizard['title'] = $info['title'];
651
      $wizard['base_table'] = $table;
652
      $wizard_plugins[$table] = $wizard;
653
    }
654
  }
655
  return $wizard_plugins;
656
}
657

    
658
/**
659
 * Helper function to define the default values for a Views wizard plugin.
660
 *
661
 * @return array
662
 *   An array of defaults for a views wizard.
663
 */
664
function views_ui_views_wizard_defaults() {
665
  return array(
666
    // The children may, for example, be a different variant for each node type.
667
    'get children' => NULL,
668
    'get child' => NULL,
669
    // Title and base table must be populated.  They are empty here just
670
    // so they are documented.
671
    'title' => '',
672
    'base_table' => NULL,
673
    // This is a callback that takes the wizard as argument and returns
674
    // an instantiazed Views UI form wizard object.
675
    'get_instance' => 'views_ui_get_form_wizard_instance',
676
    'form_wizard_class' => array(
677
      'file' => 'views_ui_base_views_wizard',
678
      'class' => 'ViewsUiBaseViewsWizard',
679
    ),
680
  );
681
}
682

    
683
/**
684
 * Inform CTools that the Views wizard plugin can have child plugins.
685
 */
686
function views_ui_ctools_plugin_type() {
687
  return array(
688
    'views_wizard' => array(
689
      'child plugins' => TRUE,
690
      'classes' => array(
691
        'form_wizard_class',
692
      ),
693
      'defaults' => views_ui_views_wizard_defaults(),
694
    ),
695
  );
696
}
697

    
698
/**
699
 * Get form wizard instance.
700
 */
701
function views_ui_get_form_wizard_instance($wizard) {
702
  if (isset($wizard['form_wizard_class']['class'])) {
703
    $class = $wizard['form_wizard_class']['class'];
704
    return new $class($wizard);
705
  }
706
  else {
707
    return new ViewsUiBaseViewsWizard($wizard);
708
  }
709
}
710

    
711
/**
712
 * Implements hook_views_plugins_alter().
713
 */
714
function views_ui_views_plugins_alter(&$plugins) {
715
  // Attach contextual links to each display plugin. The links will point to
716
  // paths underneath "admin/structure/views/view/{$view->name}" (i.e., paths
717
  // for editing and performing other contextual actions on the view).
718
  foreach ($plugins['display'] as &$display) {
719
    $display['contextual links']['views_ui'] = array(
720
      'parent path' => 'admin/structure/views/view',
721
      'argument properties' => array('name'),
722
    );
723
  }
724
}
725

    
726
/**
727
 * Implements hook_contextual_links_view_alter().
728
 */
729
function views_ui_contextual_links_view_alter(&$element, $items) {
730
  // Remove contextual links from being rendered, when so desired, such as
731
  // within a View preview.
732
  if (views_ui_contextual_links_suppress()) {
733
    $element['#links'] = array();
734
  }
735
  // Append the display ID to the Views UI edit links, so that clicking on the
736
  // contextual link takes you directly to the correct display tab on the edit
737
  // screen.
738
  elseif (!empty($element['#links']['views-ui-edit']) && !empty($element['#element']['#views_contextual_links_info']['views_ui']['view_display_id'])) {
739
    $display_id = $element['#element']['#views_contextual_links_info']['views_ui']['view_display_id'];
740
    $element['#links']['views-ui-edit']['href'] .= '/' . $display_id;
741
  }
742
}
743

    
744
/**
745
 * Sets a static variable for controlling whether contextual links are rendered.
746
 *
747
 * @see views_ui_contextual_links_view_alter()
748
 */
749
function views_ui_contextual_links_suppress($set = NULL) {
750
  $suppress = &drupal_static(__FUNCTION__);
751
  if (isset($set)) {
752
    $suppress = $set;
753
  }
754
  return $suppress;
755
}
756

    
757
/**
758
 * Increments the views_ui_contextual_links_suppress() static variable.
759
 *
760
 * When this function is added to the #pre_render of an element, and
761
 * 'views_ui_contextual_links_suppress_pop' is added to the #post_render of the
762
 * same element, then all contextual links within the element and its
763
 * descendants are suppressed from being rendered. This is used, for example,
764
 * during a View preview, when it is not desired for nodes in the Views result
765
 * to have contextual links.
766
 *
767
 * @see views_ui_contextual_links_suppress_pop()
768
 */
769
function views_ui_contextual_links_suppress_push() {
770
  views_ui_contextual_links_suppress(((int) views_ui_contextual_links_suppress()) + 1);
771
}
772

    
773
/**
774
 * Decrements the views_ui_contextual_links_suppress() static variable.
775
 *
776
 * @see views_ui_contextual_links_suppress_push()
777
 */
778
function views_ui_contextual_links_suppress_pop() {
779
  views_ui_contextual_links_suppress(((int) views_ui_contextual_links_suppress()) - 1);
780
}
781

    
782
/**
783
 * Menu callback.
784
 *
785
 * Handles AJAX form submissions similar to ajax_form_callback(), but can be
786
 * used for uncached forms.
787
 *
788
 * Ajax_form_callback(), the menu callback for the system/ajax path, requires
789
 * the form to be retrievable from the form cache, because it lacks a trusted
790
 * $form_id argument with which to call drupal_retrieve_form(). When AJAX is
791
 * wanted on a non-cacheable form, #ajax['path'] can be set to a path whose
792
 * menu router item's 'page callback' is this function, and whose
793
 * 'page arguments' is the form id, optionally followed by additional build
794
 * arguments, as expected by drupal_get_form().
795
 *
796
 * The same caution must be used when defining a hook_menu() entry with this
797
 * page callback as is used when defining a hook_menu() entry with the
798
 * 'drupal_get_form' page callback: a 'page arguments' must be specified with a
799
 * literal value as the first argument, because $form_id determines which form
800
 * builder function gets called, so must be safe from user tampering.
801
 *
802
 * @see drupal_get_form()
803
 * @see ajax_form_callback()
804
 * @see http://drupal.org/node/774876
805
 */
806
function views_ui_ajax_get_form($form_id) {
807
  $args = func_get_args();
808
  array_shift($args);
809

    
810
  // @see ajax_get_form()
811
  $form_state = array(
812
    'no_redirect' => TRUE,
813
  );
814
  $form_state['rebuild_info']['copy']['#build_id'] = TRUE;
815
  $form_state['rebuild_info']['copy']['#action'] = TRUE;
816

    
817
  // @see drupal_get_form()
818
  $form_state['build_info']['args'] = $args;
819
  $form = drupal_build_form($form_id, $form_state);
820

    
821
  // @see ajax_form_callback()
822
  if (!empty($form_state['triggering_element'])) {
823
    $callback = $form_state['triggering_element']['#ajax']['callback'];
824
  }
825
  if (!empty($callback) && function_exists($callback)) {
826
    return $callback($form, $form_state);
827
  }
828
}
829

    
830
/**
831
 * @todo move these when we can
832
 */
833

    
834
/**
835
 * Helper function to get a list of paths assigned to a view.
836
 *
837
 * @param object $view
838
 *   The view.
839
 *
840
 * @return array
841
 *   An array of links to this view's display paths.
842
 */
843
function _views_ui_get_paths($view) {
844
  $all_paths = array();
845
  if (empty($view->display)) {
846
    $all_paths[] = t('Edit this view to add a display.');
847
  }
848
  else {
849
    // Make sure all the handlers are set up.
850
    $view->init_display();
851
    foreach ($view->display as $display) {
852
      if (!empty($display->handler) && $display->handler->has_path()) {
853
        $one_path = $display->handler->get_option('path');
854

    
855
        if (empty($view->disabled) && strpos($one_path, '%') === FALSE) {
856
          // @codingStandardsIgnoreLine
857
          $all_paths[] = l('/' . $one_path, $one_path);
858
        }
859
        else {
860
          $all_paths[] = check_plain('/' . $one_path);
861
        }
862
      }
863
    }
864
  }
865

    
866
  return array_unique($all_paths);
867
}
868

    
869
/**
870
 * Helper function to get a list of displays included in a view.
871
 *
872
 * @param object $view
873
 *   The view.
874
 *
875
 * @return array
876
 *   An array of display types that this view includes.
877
 */
878
function _views_ui_get_displays_list($view) {
879
  $displays = array();
880
  foreach ($view->display as $display) {
881
    if (!empty($display->handler->definition['admin'])) {
882
      $displays[$display->handler->definition['admin']] = TRUE;
883
    }
884
  }
885

    
886
  if ($displays) {
887
    ksort($displays);
888
    $displays = array_keys($displays);
889
  }
890
  return $displays;
891
}
892

    
893
/**
894
 * This is part of a patch to address a jQueryUI bug.
895
 *
896
 * The bug is responsible
897
 * for the inability to scroll a page when a modal dialog is active. If the
898
 * content of the dialog extends beyond the bottom of the viewport, the user is
899
 * only able to scroll with a mousewheel or up/down keyboard keys.
900
 *
901
 * @see http://bugs.jqueryui.com/ticket/4671
902
 * @see https://bugs.webkit.org/show_bug.cgi?id=19033
903
 * @see /js/jquery.ui.dialog.patch.js
904
 * @see /js/jquery.ui.dialog.min.js
905
 *
906
 * The JavaScript patch overwrites the $.ui.dialog.overlay.events object to
907
 * remove the mousedown, mouseup and click events from the list of events that
908
 * are bound in $.ui.dialog.overlay.create.
909
 */
910
function views_ui_library_alter(&$libraries, $module) {
911
  if ($module == 'system' && isset($libraries['ui.dialog'])) {
912
    // Only apply the fix, if we don't have an up to date jQueryUI version.
913
    if (version_compare($libraries['ui.dialog']['version'], '1.7.2', '>=') && version_compare($libraries['ui.dialog']['version'], '1.10.0', '<')) {
914
      $libraries['ui.dialog']['js'][drupal_get_path('module', 'views') . '/js/jquery.ui.dialog.patch.js'] = array();
915
    }
916
  }
917
}
918

    
919
/**
920
 * Truncate strings to a set length and provide a ... if they truncated.
921
 *
922
 * This is often used in the UI to ensure long strings fit.
923
 */
924
function views_ui_truncate($string, $length) {
925
  if (drupal_strlen($string) > $length) {
926
    $string = drupal_substr($string, 0, $length);
927
    $string .= '...';
928
  }
929

    
930
  return $string;
931
}