Projet

Général

Profil

Paste
Télécharger (29,6 ko) Statistiques
| Branche: | Révision:

root / drupal7 / sites / all / modules / views / views_ui.module @ ef1afbb9

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
439
 *    Perhaps move this to includes/admin.inc or theme/theme.inc
440
 */
441
function template_preprocess_views_ui_view_preview_section(&$vars) {
442
  switch ($vars['section']) {
443
    case 'title':
444
      $vars['title'] = t('Title');
445
      $links = views_ui_view_preview_section_display_category_links($vars['view'], 'title', $vars['title']);
446
      break;
447

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
557
  return $links;
558
}
559

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

    
573
  return $links;
574
}
575

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

    
581
  $links = array();
582

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

    
589
  return $links;
590
}
591

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
867
  return array_unique($all_paths);
868
}
869

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

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

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

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

    
931
  return $string;
932
}