2
// $Id: admin.inc,v 1.154 2009/04/07 20:48:28 merlinofchaos Exp $
5
* Provides the Views' administrative interface.
9
* Page callback to list views in the system.
11
function views_ui_list_views($arg = NULL) {
13
return drupal_not_found();
16
$output = theme('views_ui_list_views');
17
views_ui_check_advanced_help();
22
* Check to see if the advanced help module is installed, and if not put up
25
* Only call this function if the user is already in a position for this to
28
function views_ui_check_advanced_help() {
29
if (variable_get('views_hide_help_message', FALSE)) {
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'))));
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'))));
45
* Preprocess the list views theme
47
function template_preprocess_views_ui_list_views(&$vars) {
51
$views = views_get_all_views();
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');
59
if (count($_GET) <= 1) {
60
if (isset($_SESSION['views']['#admin']) && is_array($_SESSION['views']['#admin'])) {
61
$_GET += $_SESSION['views']['#admin'];
65
$_SESSION['views']['#admin'] = $_GET;
66
unset($_SESSION['views']['#admin']['q']);
74
'no_redirect' => TRUE,
77
$vars['widgets'] = drupal_build_form('views_ui_list_views_form', $form_state);
79
$vars['help_type_icon'] = theme('advanced_help_topic', 'views', 'view-type');
81
$base_tables = views_fetch_base_tables();
83
foreach ($views as $view) {
84
if ($form_state['values']['tag'] != 'all') {
85
if ($form_state['values']['tag'] == 'none') {
86
if (!empty($view->tag)) {
90
else if ($form_state['values']['tag'] != $view->tag) {
94
if ($form_state['values']['type'] != 'all' && $form_state['values']['type'] != $view->type) {
98
if ($form_state['values']['base'] != 'all' && $form_state['values']['base'] != $view->base_table) {
102
if ($form_state['values']['display'] != 'all' && empty($view->display[$form_state['values']['display']])) {
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");
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");
118
if (empty($view->disabled)) {
119
$item->ops[] = l(t('Disable'), "admin/build/views/disable/$view->name", array('query' => drupal_get_destination()));
122
$item->ops[] = l(t('Enable'), "admin/build/views/enable/$view->name", array('query' => drupal_get_destination()));
126
$item->ops = implode(' | ', $item->ops);
127
if (empty($view->display)) {
128
$item->path = t('Warning! Broken view!');
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);
135
$item->type = $view->type;
136
$item->name = $view->name;
138
if (!empty($view->tag)) {
139
$item->tag = $view->tag;
142
$item->title = $view->get_title();
143
$item->base = !empty($base_tables[$view->base_table]['title']) ? $base_tables[$view->base_table]['title'] : t('Broken');
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;
152
if ($item->displays) {
153
ksort($item->displays);
154
$item->displays = implode(', ', array_keys($item->displays));
157
$item->description = check_plain($view->description);
158
$item->classes = empty($view->disabled) ? 'view-enabled' : 'view-disabled';
161
$sort = intval(empty($view->disabled) xor $form_state['values']['sort'] == 'asc');
163
switch ($form_state['values']['order']) {
166
$sort .= strtolower($view->name);
169
$sort .= strtolower($item->title);
172
$sort .= strtolower($raw_path); // $path;
175
$sort .= $view->type . $view->name;
178
$sort .= strtolower($view->tag);
181
$sort .= strtolower($view->description);
188
if ($form_state['values']['sort'] == 'desc') {
196
foreach ($sorts as $id => $title) {
200
views_add_css('views-list');
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');
208
$vars['help'] = t('Not sure what to do? Try the "!getting-started" page.', array('!getting-started' => $getting_started));
212
* Provide a form for sorting and filtering the list of views.
214
function views_ui_list_views_form(&$form_state) {
215
if (!variable_get('clean_url', FALSE)) {
218
'#value' => $_GET['q'],
222
$all = array('all' => t('<All>'));
223
$none = array('none' => t('<None>'));
225
$form['type'] = array(
227
'#title' => t('Storage'),
230
t('Normal') => t('Normal'),
231
t('Default') => t('Default'),
232
t('Overridden') => t('Overridden'),
234
'#default_value' => 'all',
238
foreach (views_fetch_base_tables() as $table => $info) {
239
$bases[$table] = $info['title'];
242
$form['base'] = array(
244
'#title' => t('Type'),
245
'#options' => array_merge($all, $bases),
246
'#default_value' => 'all',
252
foreach ($form_state['views'] as $name => $view) {
253
if (!empty($view->tag)) {
254
$tags[$view->tag] = $view->tag;
260
$form['tag'] = array(
262
'#title' => t('Tag'),
263
'#options' => array_merge($all, $none, $tags),
264
'#default_value' => 'all',
268
foreach (views_fetch_plugin_data('display') as $id => $info) {
269
if (!empty($info['admin'])) {
270
$displays[$id] = $info['admin'];
276
$form['display'] = array(
278
'#title' => t('Displays'),
279
'#options' => array_merge($all, $displays),
280
'#default_value' => 'all',
283
$form['order'] = array(
285
'#title' => t('Sort by'),
288
'title' => t('Title'),
292
'desc' => t('Description'),
294
'#default_value' => 'name',
297
$form['sort'] = array(
299
'#title' => t('Order'),
304
'#default_value' => 'asc',
307
$form['submit'] = array(
308
'#name' => '', // so it won't in the $_GET args
310
'#id' => 'edit-views-apply',
311
'#value' => t('Apply'),
314
if (!empty($_SESSION['views']['#admin'])) {
315
$form['reset'] = array(
317
'#id' => 'edit-views-reset',
318
'#value' => t('Reset'),
322
$form['#theme'] = array('views_ui_list_views_form');
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);
335
* Page callback for the live preview.
337
* @todo make this use a template
339
function views_ui_preview($js, $view) {
340
// Take off the items we know so that we can have just the args passed
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';
348
'display_id' => $display_id,
349
'view_args' => $func_args ? implode('/', $func_args) : '',
351
'no_redirect' => TRUE,
356
$output = drupal_build_form('views_ui_preview_form', $form_state);
358
if (isset($form_state['view_args']) && $form_state['view_args'] !== '') {
359
$args = explode('/', $form_state['view_args']);
362
$errors = $view->validate();
363
if ($errors === TRUE) {
365
$view->live_preview = TRUE;
367
// Store the current view URL for later use:
368
$view->set_display($form_state['display_id']);
369
$view->set_arguments($args);
371
if ($view->display_handler->get_option('path')) {
372
$path = $view->get_url();
375
// Make view links come back to preview.
376
$view->override_path = 'admin/build/views/nojs/preview/' . $view->name . '/' . $form_state['display_id'];
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'];
384
$preview = $view->preview($form_state['display_id'], $args);
386
// Get information from the preview for display.
387
if (!empty($view->build_info['query'])) {
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);
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) {
401
$queries .= t('[@time ms]', array('@time' => intval($query[1] * 100000) / 100)) . ' ' . $query[0];
404
$rows[] = array('<strong>' . t('Other queries') . '</strong>', '<pre>' . $queries . '</pre>');
407
$rows[] = array('<strong>' . t('Title') . '</strong>', filter_xss_admin($view->get_title()));
409
$path = l($path, $path);
412
$path = t('This display has no path.');
415
$rows[] = array('<strong>' . t('Path') . '</strong>', $path);
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);
422
$info = theme('table', array(), $rows);
425
$info = theme('table', array(), array(array('<strong>' . t('Query') . '</strong>', t('No query was run'))));
429
foreach ($errors as $error) {
430
drupal_set_message($error, 'error');
432
$preview = t('Unable to preview due to validation errors.');
436
$info = '<div class="views-query-info">' . $info . '</div>';
438
if (variable_get('views_ui_query_on_top', FALSE)) {
439
$output .= $info . $preview;
442
$output .= $preview . $info;
446
views_add_css('views-admin');
447
drupal_set_title($view->get_title());
451
views_include('ajax');
452
$object = new stdClass();
453
if (!empty($view->js_settings)) {
454
$object->js = $view->js_settings;
456
$object->display = '';
457
if ($messages = theme('status_messages')) {
458
$object->display = '<div class="views-messages">' . $messages . '</div>';
460
$object->display .= $output;
461
$object->title = $view->get_title();
462
views_ajax_render($object);
467
* Form for generating argument information for the live preview.
469
function views_ui_preview_form(&$form_state) {
470
$view = &$form_state['view'];
471
$view->init_display();
473
foreach ($view->display as $id => $display) {
474
$options[$id] = $display->display_title;
477
$form['#attributes'] = array(
478
'class' => 'clear-block',
481
$form['display_id'] = array(
483
'#title' => t('Display'),
484
'#options' => $options,
485
'#default_value' => $form_state['display_id'],
486
'#id' => 'preview-display-id',
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',
497
$form['preview'] = array(
499
'#value' => t('Preview'),
500
'#id' => 'preview-submit',
503
$form['#action'] = url("admin/build/views/nojs/preview/$view->name");
508
* Submit the preview form.
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.
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'];
519
* Page callback to add a new view.
521
function views_ui_add_page() {
526
return drupal_build_form('views_ui_add_form', $form_state);
530
* Page callback to add a new view.
532
function views_ui_clone_page($view) {
534
'view' => $view->copy(),
537
drupal_set_title(t('Clone view %view', array('%view' => $view->name)));
538
return drupal_build_form('views_ui_add_form', $form_state);
542
* Form constructor callback to create the views Add Form, phase 1.
544
function views_ui_add_form(&$form_state) {
545
$view = $form_state['view'];
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.'),
554
'#default_value' => $view ? $view->name : '',
555
'#attributes' => array('dir'=>'ltr'),
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 : '',
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',
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>';
578
$form['base_table'] = array(
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,
587
$form['base_table']['#disabled'] = TRUE;
590
$form['submit'] = array(
592
'#value' => t('Next'),
593
'#validate' => array('views_ui_add_form_validate'),
594
'#submit' => array('views_ui_add_form_submit'),
601
* Validate the add view form.
603
function views_ui_add_form_validate($form, &$form_state) {
604
$name = $form_state['values']['name'];
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.'));
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.'));
619
* Process the add view form
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'];
630
views_ui_cache_set($view);
631
$form_state['redirect'] ='admin/build/views/edit/' . $view->name;
635
* Page to delete a view.
637
function views_ui_delete_confirm(&$form_state, $view) {
638
$form_state['view'] = &$view;
641
$cancel = 'admin/build/views';
642
if (!empty($_REQUEST['cancel'])) {
643
$cancel = $_REQUEST['cancel'];
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');
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');
657
return confirm_form($form,
666
* Submit handler to delete a view.
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';
676
* Page to delete a view.
678
function views_ui_break_lock_confirm(&$form_state, $view) {
679
$form_state['view'] = &$view;
682
if (empty($view->locked)) {
683
return t('There is no lock on view %view to break.', array('%name' => $view->name));
686
$cancel = 'admin/build/views/edit/' . $view->name;
687
if (!empty($_REQUEST['cancel'])) {
688
$cancel = $_REQUEST['cancel'];
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)),
696
t('By breaking this lock, any unsaved changes made by !user will be lost!', array('!user' => theme('username', $account))),
702
* Submit handler to break_lock a view.
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.'));
711
* The main view edit page
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();
721
* Export a view for cut & paste.
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,
736
* Import a view from cut & paste
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.'),
745
$form['view'] = array(
746
'#type' => 'textarea',
747
'#title' => t('Paste view code here'),
750
$form['submit'] = array(
752
'#value' => t('Import'),
753
'#submit' => array('views_ui_import_submit'),
754
'#validate' => array('views_ui_import_validate'),
760
* Validate handler to import a view
762
function views_ui_import_validate($form, &$form_state) {
763
views_include('view');
765
eval($form_state['values']['view']);
768
if (!is_object($view)) {
769
form_error($form['view'], t('Unable to interpret view code.'));
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');
780
form_error($form['view'], t('That view is not compatible with this version of Views.'));
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.'));
789
if ($form_state['values']['name']) {
790
$view->name = $form_state['values']['name'];
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'));
798
$view->init_display();
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');
809
$plugin = views_get_plugin('style', $display->handler->get_option('style_plugin'));
811
drupal_set_message(t('Style plugin @plugin is not available.', array('@plugin' => $display->handler->get_option('style_plugin'))), 'error');
814
else if ($plugin->uses_row_plugin()) {
815
$plugin = views_get_plugin('row', $display->handler->get_option('row_plugin'));
817
drupal_set_message(t('Row plugin @plugin is not available.', array('@plugin' => $display->handler->get_option('row_plugin'))), 'error');
822
foreach (views_object_types() as $type => $info) {
823
$handlers = $display->handler->get_handlers($type);
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,
840
form_set_error('', t('Unable to import view.'));
843
$form_state['view'] = &$view;
847
* Submit handler for view import
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;
856
* The main edit view form, which is really just a save/cancel/delete button.
858
function views_ui_edit_view_form(&$form_state, $view) {
859
$form['buttons']['save'] = array(
861
'#value' => t('Save'),
862
'#validate' => array('views_ui_edit_view_form_validate'),
863
'#submit' => array('views_ui_edit_view_form_submit'),
866
$form['buttons']['cancel'] = array(
868
'#value' => t('Cancel'),
869
'#submit' => array('views_ui_edit_view_form_cancel'),
872
if (is_numeric($view->vid)) {
873
$form['buttons']['delete'] = array(
875
'#value' => t('Delete'),
876
'#submit' => array('views_ui_edit_view_form_delete'),
880
$form_state['view'] = &$view;
885
* Validate that a view is complete and whole.
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')) {
893
$errors = $form_state['view']->validate();
894
if ($errors !== TRUE) {
895
foreach ($errors as $error) {
896
form_set_error('', $error);
902
* Submit handler for the edit view form.
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]);
912
$form_state['view']->save();
913
drupal_set_message(t('The view has been saved.'));
915
// Make sure menu items get rebuilt as neces
918
// Clear the views cache.
919
cache_clear_all('*', 'cache_views');
921
// Clear the page cache.
924
// Remove this view from cache so we can edit it properly.
925
views_object_cache_clear('view', $form_state['view']->name);
929
* Submit handler for the edit view form.
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');
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);
948
* Preprocess the view edit page.
950
function template_preprocess_views_ui_edit_view(&$vars) {
951
$view = &$vars['view'];
953
$vars['save_button'] = drupal_get_form('views_ui_edit_view_form', $view);
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');
959
views_include('tabs');
960
$tabs = new views_tabset;
962
$vars['message'] = '<div class="message">' . t("Click on an item to edit that item's details.") . '</div>';
964
if (!$view->set_display('default')) {
965
drupal_set_message(t('This view has a broken default display and cannot be used.'), 'error');
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);
974
// This is the area that will render beneath the links
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);
984
$vars['tabs'] = $tabs->render();
987
'display_id' => 'default',
990
'no_redirect' => TRUE,
994
$vars['preview'] = drupal_build_form('views_ui_preview_form', $form_state);
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);
1004
$vars['quick_links_raw'] = array(
1006
'title' => t('Export'),
1007
'alt' => t("Export this view"),
1008
'href' => "admin/build/views/export/$view->name",
1011
'title' => t('Clone'),
1012
'alt' => t("Create a copy of this view"),
1013
'href' => "admin/build/views/clone/$view->name",
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"),
1027
// Displays can have the same path; no point in showing more than one link.
1028
$paths[$path] = TRUE;
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');
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);
1051
$settings = array('views' => array('ajax' => array(
1052
'id' => '#views-ajax-pad',
1053
'title' => '#views-ajax-title',
1054
'defaultForm' => $vars['message'],
1057
drupal_add_js($settings, 'setting');
1060
function template_preprocess_views_ui_edit_tab(&$vars) {
1061
$view = $vars['view'];
1062
$display = $vars['display'];
1063
$plugin = $display->handler->definition;
1065
$top = $left = $middle = $right = '';
1067
// If this form was submitted it was already handled, so force it not to
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']);
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);
1080
$vars['title'] = check_plain($display->display_title);
1081
$vars['description'] = check_plain($plugin['help']);
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;
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')));
1093
// Calculate options from display plugin.
1094
$options = $categories = array();
1095
$display->handler->options_summary($categories, $options);
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();
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;
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');
1116
if (!empty($option['title'])) {
1117
$data['content'] .= $option['title'] . ': ';
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;
1126
$display_id = $display->id;
1127
if (!$display->handler->is_default_display()) {
1128
if ($display->handler->defaultable_sections($id)) {
1129
$data['overridden'] = TRUE;
1133
$data['class'] = views_ui_item_css($display_id . '-' . $id);
1134
if (!empty($view->changed_sections[$display_id . '-' . $id])) {
1135
$data['changed'] = TRUE;
1139
$vars['categories'] = $categories;
1142
if (isset($plugin['help topic'])) {
1143
$vars['display_help_icon'] = theme('advanced_help_topic', $plugin['module'], $plugin['help topic']);
1146
$vars['display_help_icon'] = '';
1149
// Fetch style plugin info because it has some effect on how/what we render.
1150
$style_plugin = $display->handler->get_plugin();
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);
1161
* Generate the summary output for a single display to render in a tab.
1163
function views_ui_display_tab($view, $display) {
1164
if (isset($display->handler)) {
1165
$plugin = $display->handler->definition;
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)));
1171
// @todo We can do a better 'plugin does not exist' tab.
1174
// The display should always be initialized prior to this call.
1175
if (empty($display->handler)) {
1179
$body = theme('views_ui_edit_tab', $view, $display);
1180
return array($display->display_title, $body);
1184
* Add information about a section to a display.
1186
function template_preprocess_views_ui_edit_item(&$vars) {
1187
$type = $vars['type'];
1188
$view = $vars['view'];
1189
$display = $vars['display'];
1191
$types = views_object_types();
1193
$vars['overridden'] = FALSE;
1194
$vars['defaulted'] = FALSE;
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;
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));
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));
1208
if (!$display->handler->is_default_display()) {
1209
if (!$display->handler->is_defaulted($types[$type]['plural'])) {
1210
$vars['overridden'] = TRUE;
1213
$vars['defaulted'] = TRUE;
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')));
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)) {
1232
$handler->init($view, $relationship);
1233
$relationships[$id] = $handler->label();
1237
// @todo: get_handlers()
1238
foreach ($display->handler->get_option($types[$type]['plural']) as $id => $field) {
1239
$fields[$id] = array();
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'] = '';
1248
$handler->init($view, $field);
1250
$field_name = $handler->ui_name(TRUE);
1251
if (!empty($field['relationship']) && !empty($relationships[$field['relationship']])) {
1252
$field_name = '(' . $relationships[$field['relationship']] . ') ' . $field_name;
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;
1260
$fields[$id]['info'] = $handler->admin_summary();
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));
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';
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));
1275
$fields[$pid]['title'] = ' ' . t(' 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;
1280
$fields[$pid]['info'] = '';
1284
$vars['fields'] = $fields;
1285
$vars['item_help_icon'] = theme('advanced_help_topic', 'views', $type);
1289
* Regenerate the tabs for AJAX updates.
1291
function views_ui_regenerate_tabs(&$view, $display_id = NULL, $object = NULL) {
1292
if (empty($display_id)) {
1293
$displays = array_keys($view->display);
1295
elseif (!is_array($display_id)) {
1296
$displays = array($display_id);
1297
if ($display_id != 'default') {
1298
$displays[] = 'default';
1302
$displays = $display_id;
1305
if (!$view->set_display('default')) {
1306
views_ajax_render(t('Invalid display id found while regenerating tabs'));
1309
if (!is_object($object)) {
1310
$object = new stdClass();
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;
1320
if (!empty($view->changed)) {
1321
$object->changed = TRUE;
1324
views_ajax_render($object);
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.
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>',
1339
$name = t('Update');
1341
// remove default validate handler
1342
$form['#validate'] = array();
1344
if (empty($form_state['ok_button'])) {
1345
// but be sure submit button validates!
1346
$form['buttons']['submit'] = array(
1347
'#type' => 'submit',
1349
'#submit' => array($form_id . '_submit'),
1350
'#validate' => array('views_ui_standard_submit', $form_id . '_validate'),
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(),
1363
if (empty($submit)) {
1366
$third_submit = function_exists($form_id . '_' . $submit) ? $form_id . '_' . $submit : 'views_ui_standard_cancel';
1368
$form['buttons'][$submit] = array(
1369
'#type' => 'submit',
1371
'#validate' => array(),
1372
'#submit' => array($third_submit),
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'];
1381
if (isset($form['#help_topic'])) {
1382
$form_state['help_topic'] = $form['#help_topic'];
1384
if (isset($form['#help_module'])) {
1385
$form_state['help_module'] = $form['#help_module'];
1387
if (isset($form['#url'])) {
1388
$form_state['url'] = $form['#url'];
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']);
1395
$form_state['js settings'] = $form['#js'];
1398
if (isset($form['#section'])) {
1399
$form_state['#section'] = $form['#section'];
1401
// Finally, we never want these cached -- our object cache does that for us.
1402
$form['#no_cache'] = TRUE;
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']);
1408
views_add_css('views-admin');
1412
* Basic submit handler applicable to all 'standard' forms
1414
function views_ui_standard_submit($form, &$form_state) {
1415
if (!empty($form['#section'])) {
1416
$form_state['view']->changed_sections[$form['#section']] = TRUE;
1421
* Submit handler for cancel button
1423
function views_ui_standard_cancel($form, &$form_state) {
1424
$form_state['redirect'] = 'admin/build/views/edit/' . $form_state['view']->name;
1427
// --------------------------------------------------------------------------
1428
// Various subforms for editing the pieces of a view.
1430
function views_ui_ajax_forms($key = NULL) {
1433
'form_id' => 'views_ui_edit_display_form',
1434
'args' => array('section'),
1436
'remove-display' => array(
1437
'form_id' => 'views_ui_remove_display_form',
1440
'config-type' => array(
1441
'form_id' => 'views_ui_config_type_form',
1442
'args' => array('type'),
1444
'rearrange' => array(
1445
'form_id' => 'views_ui_rearrange_form',
1446
'args' => array('type'),
1448
'add-item' => array(
1449
'form_id' => 'views_ui_add_item_form',
1450
'args' => array('type'),
1452
'config-item' => array(
1453
'form_id' => 'views_ui_config_item_form',
1454
'args' => array('type', 'id'),
1456
'config-item-extra' => array(
1457
'form_id' => 'views_ui_config_item_extra_form',
1458
'args' => array('type', 'id'),
1460
'change-style' => array(
1461
'form_id' => 'views_ui_change_style_form',
1462
'args' => array('type', 'id'),
1464
'config-style' => array(
1465
'form_id' => 'views_ui_config_style_form',
1466
'args' => array('type', 'id'),
1471
return !empty($forms[$key]) ? $forms[$key] : NULL;
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.
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));
1486
foreach ($form['args'] as $id) {
1487
$arg = (!empty($args)) ? array_shift($args) : NULL;
1488
$identifier .= '-' . $arg;
1494
* Build up a $form_state object suitable for use with drupal_build_form
1495
* based on known information about a form.
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(
1502
'form_id' => $form['form_id'],
1505
'display_id' => $display_id,
1506
'no_redirect' => TRUE,
1509
foreach ($form['args'] as $id) {
1510
$form_state[$id] = (!empty($args)) ? array_shift($args) : NULL;
1517
* Create the URL for one of our standard AJAX forms based upon known
1518
* information about the form.
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];
1532
* Add another form to the stack; clicking 'update' will go to this form
1533
* rather than closing the ajax pad.
1535
function views_ui_add_form_to_stack($key, &$view, $display_id, $args, $top = FALSE) {
1536
if (empty($view->stack)) {
1537
$view->stack = array();
1540
$stack = array(views_ui_build_identifier($key, $view, $display_id, $args), $key, &$view, $display_id, $args);
1542
array_unshift($view->stack, $stack);
1545
$view->stack[] = $stack;
1550
* Generic entry point to handle forms.
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.
1557
function views_ui_ajax_form($js, $key, &$view, $display_id) {
1558
$form = views_ui_ajax_forms($key);
1560
return drupal_not_found();
1563
views_include('ajax');
1564
$args = func_get_args();
1565
// Remove the known args
1566
array_splice($args, 0, 4);
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
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();
1580
$output = views_ajax_form_wrapper($form_state['form_id'], $form_state);
1583
// Sometimes we need to re-generate the form for multi-step type operations.
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.
1593
return drupal_goto(views_ui_build_form_url($form_state));
1595
$object = views_ajax_form_wrapper($form_state['form_id'], $form_state);
1596
$object->url = url(views_ui_build_form_url($form_state));
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");
1602
// regenerate all tabs because changes to the default tab could ripple.
1603
return views_ui_regenerate_tabs($view, NULL, $object);
1606
return ($js) ? views_ajax_render($output) : $output;
1610
* AJAX callback to add a display.
1612
function views_ui_add_display($js, $view) {
1613
views_include('ajax');
1614
$form_state = array(
1619
$output = views_ajax_form_wrapper('views_ui_add_display_form', $form_state);
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'];
1626
// Make sure the new display is active
1627
if (!$view->set_display('default')) {
1628
views_ajax_render(t('Unable to initialize default display'));
1631
// Render the new display
1632
list($title, $body) = views_ui_display_tab($view, $view->display[$id]);
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));
1638
// Render the command object. This automatically exits.
1639
views_ajax_render($output);
1642
// But the non-js variant will return output if it didn't redirect us.
1647
* Form to add a display to a view.
1649
function views_ui_add_display_form(&$form_state) {
1650
$view = &$form_state['view'];
1652
$form['display']['display'] = array(
1653
'#type' => 'select',
1654
'#options' => views_fetch_plugin_names('display'),
1655
'#default_value' => 'page',
1658
$form['display']['add_display'] = array(
1659
'#type' => 'submit',
1660
'#value' => t('Add display'),
1661
'#submit' => array('views_ui_add_display_form_submit'),
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");
1672
* Submit handler to add a display to a view.
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);
1680
views_ui_cache_set($form_state['view']);
1683
$form_state['redirect'] = array('admin/build/views/edit/' . $form_state['view']->name, NULL, 'views-tab-' . $form_state['id']);
1687
* Form to remove a display from a view.
1689
function views_ui_remove_display_form(&$form_state) {
1690
$view = &$form_state['view'];
1691
$display_id = $form_state['display_id'];
1693
if (empty($view->display[$display_id]->deleted)) {
1694
$form['display'] = array(
1695
'#prefix' => '<div class="display-button remove-display">',
1696
'#suffix' => '</div>',
1698
$form['remove_display'] = array(
1699
'#type' => 'submit',
1700
'#value' => t('Remove display'),
1701
'#submit' => array('views_ui_remove_display_form_submit'),
1705
$form['display'] = array(
1706
'#prefix' => '<div class="display-button restore-display">',
1707
'#suffix' => '</div>',
1709
$form['restore_display'] = array(
1710
'#type' => 'submit',
1711
'#value' => t('Restore display'),
1712
'#submit' => array('views_ui_remove_display_form_restore'),
1715
$form['#action'] = url("admin/build/views/nojs/remove-display/$view->name/$display_id");
1716
$form['#attributes'] = array('class' => 'views-ajax-form');
1722
* Submit handler to add a remove to a display from a view.
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;
1732
views_ui_cache_set($form_state['view']);
1737
* Submit handler to add a restore a removed display to a view.
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;
1745
views_ui_cache_set($form_state['view']);
1749
* Page callback to display analysis information on a view.
1751
function views_ui_analyze_view($js, $view) {
1752
views_include('ajax');
1753
$form_state = array(
1758
$output = views_ajax_form_wrapper('views_ui_analyze_view_form', $form_state);
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);
1765
return views_ajax_render($output);
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.
1775
* It has no submit or anything, as we will never actually submit this form
1776
* where the form is placed.
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'),
1790
* Form constructor callback to display analysis information on a view
1792
function views_ui_analyze_view_form(&$form_state) {
1793
$view = &$form_state['view'];
1795
$form['#title'] = t('View analysis');
1796
$form['#section'] = 'analyze';
1798
views_include('analyze');
1799
$messages = views_analyze_view($view);
1801
$form['analysis'] = array(
1802
'#prefix' => '<div class="form-item">',
1803
'#suffix' => '</div>',
1804
'#value' => views_analyze_format_result($view, $messages),
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');
1814
* Submit handler for views_ui_analyze_view_form
1816
function views_ui_analyze_view_form_submit($form, &$form_state) {
1817
$form_state['redirect'] = 'admin/build/views/edit/' . $form_state['view']->name;
1821
* Page callback to edit details of a view.
1823
function views_ui_edit_details($js, $view) {
1824
views_include('ajax');
1825
$form_state = array(
1830
$output = views_ajax_form_wrapper('views_ui_edit_details_form', $form_state);
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);
1837
return views_ajax_render($output);
1844
* Form constructor callback to edit details of a view
1846
function views_ui_edit_details_form(&$form_state) {
1847
$view = &$form_state['view'];
1849
$form['#title'] = t('View details');
1850
$form['#section'] = 'details';
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,
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',
1867
views_ui_standard_form_buttons($form, $form_state, 'views_ui_edit_details_form');
1872
* Submit handler for views_ui_edit_details_form
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;
1882
* Form constructor callback to edit display of a view
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'];
1889
if (!$view->set_display($display_id)) {
1890
views_ajax_render(t('Invalid display id @display', array('@display' => $display_id)));
1892
$display = &$view->display[$display_id];
1894
// Get form from the handler.
1895
$display->handler->options_form($form, $form_state);
1897
if (isset($form_state['update_name'])) {
1898
$name = $form_state['update_name'];
1901
views_ui_standard_form_buttons($form, $form_state, 'views_ui_edit_display_form', $name);
1906
* Validate handler for views_ui_edit_display_form
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);
1914
* Submit handler for views_ui_edit_display_form
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);
1920
views_ui_cache_set($form_state['view']);
1924
* Override handler for views_ui_edit_display_form
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);
1930
views_ui_cache_set($form_state['view']);
1931
$form_state['rerender'] = TRUE;
1932
$form_state['rebuild'] = TRUE;
1935
* Form to config items in the views UI.
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'];
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)));
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';
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']);
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);
1963
if (isset($form_state['update_name'])) {
1964
$name = $form_state['update_name'];
1967
views_ui_standard_form_buttons($form, $form_state, 'views_ui_config_type_form', $name);
1972
* Submit handler for type configuration form
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']];
1979
views_ui_cache_set($form_state['view']);
1983
* Configure settings particular to filters.
1985
function views_ui_config_filters_form(&$form, &$form_state) {
1990
* Form to rearrange items in the views UI.
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'];
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)));
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';
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']);
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)) {
2021
$handler->init($view, $relationship);
2022
$relationships[$id] = $handler->label();
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',
2031
'#default_value' => ++$count,
2033
$handler = views_get_handler($field['table'], $field['field'], $type);
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;
2041
$form[$id]['name'] = array(
2046
$form[$id]['name'] = array('#value' => t('Broken field @id', array('@id' => $id)));
2048
$form[$id]['removed'] = array(
2049
'#type' => 'checkbox',
2050
'#id' => 'views-removed-' . $id,
2051
'#attributes' => array('class' => 'views-remove-checkbox'),
2052
'#default_value' => 0,
2056
// Add javascript settings that will be added via $.extend for tabledragging
2057
$form['#js']['tableDrag']['arrange']['weight'][0] = array(
2058
'target' => 'weight',
2060
'relationship' => 'sibling',
2061
'action' => 'order',
2067
if (isset($form_state['update_name'])) {
2068
$name = $form_state['update_name'];
2071
views_ui_standard_form_buttons($form, $form_state, 'views_ui_rearrange_form');
2076
* Turn the rearrange form into a proper table
2078
function theme_views_ui_rearrange_form($form) {
2080
foreach (element_children($form) as $id) {
2081
if (isset($form[$id]['name'])) {
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));
2088
$rows[] = array('data' => $row, 'class' => 'draggable', 'id' => 'views-row-' . $id);
2092
$rows[] = array(array('data' => t('No fields available.'), 'colspan' => '2'));
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);
2105
* Submit handler for rearranging form
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']];
2111
$old_fields = $display->handler->get_option($types[$form_state['type']]['plural']);
2112
$new_fields = $order = array();
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'];
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];
2130
$display->handler->set_option($types[$form_state['type']]['plural'], $new_fields);
2133
views_ui_cache_set($form_state['view']);
2137
* Form to add_item items in the views UI.
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'];
2144
if (!$view->set_display($display_id)) {
2145
views_ajax_render(t('Invalid display id @display', array('@display' => $display_id)));
2147
$display = &$view->display[$display_id];
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';
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);
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'),
2167
$form['name'] = array(
2168
'#prefix' => '<div class="views-radio-box form-checkboxes">',
2169
'#suffix' => '</div>',
2171
'#default_value' => 'all',
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,
2186
$form['group']['#options'] = $groups;
2189
$form['markup'] = array(
2190
'#value' => '<div class="form-item">' . t('There are no @types available to add.', array('@types' => $types[$type]['ltitle'])) . '</div>',
2193
views_ui_standard_form_buttons($form, $form_state, 'views_ui_add_item_form', t('Add'));
2199
* Submit handler for adding new item(s) to a view.
2201
function views_ui_add_item_form_submit($form, &$form_state) {
2202
$type = $form_state['type'];
2203
$types = views_object_types();
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);
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));
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));
2222
views_ui_cache_set($form_state['view']);
2227
* Form to config_item items in the views UI.
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'];
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)));
2239
$item = $view->get_item($display_id, $type, $id);
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'])));
2247
$handler->init($view, $item);
2248
$types = views_object_types();
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']);
2255
// A whole bunch of code to figure out what relationships are valid for
2257
$relationships = $view->display_handler->get_option('relationships');
2258
$relationship_options = array();
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']) {
2266
$relationship_handler = views_get_handler($relationship['table'], $relationship['field'], 'relationship');
2267
// ignore invalid/broken relationships.
2268
if (empty($relationship_handler)) {
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();
2282
if (!empty($relationship_options)) {
2283
// Make sure the existing relationship is even valid. If not, force
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);
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);
2300
$form['options']['relationship'] = array(
2301
'#type' => 'select',
2302
'#title' => t('Relationship'),
2303
'#options' => $relationship_options,
2304
'#default_value' => $rel,
2308
$form['options']['relationship'] = array(
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()));
2317
$form['#section'] = $display_id . '-' . $type . '-' . $id;
2319
// Get form from the handler.
2320
$handler->options_form($form['options'], $form_state);
2321
$form_state['handler'] = &$handler;
2325
if (isset($form_state['update_name'])) {
2326
$name = $form_state['update_name'];
2329
views_ui_standard_form_buttons($form, $form_state, 'views_ui_config_item_form', $name, t('Remove'), 'remove');
2335
* Submit handler for configing new item(s) to a view.
2337
function views_ui_config_item_form_validate($form, &$form_state) {
2338
$form_state['handler']->options_validate($form['options'], $form_state);
2342
* Submit handler for configing new item(s) to a view.
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;
2350
unset($form_state['values']['options']['expose_button']);
2352
// Store the data we're given.
2353
foreach ($form_state['values']['options'] as $key => $value) {
2354
$item[$key] = $value;
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);
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);
2367
views_ui_cache_set($form_state['view']);
2371
* Submit handler for removing an item from a view
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);
2378
views_ui_cache_set($form_state['view']);
2382
* Override handler for views_ui_edit_display_form
2384
function views_ui_config_item_form_expose($form, &$form_state) {
2385
$item = &$form_state['handler']->options;
2387
$item['exposed'] = empty($item['exposed']);
2389
// If necessary, set new defaults:
2390
if ($item['exposed']) {
2391
$form_state['handler']->expose_options();
2394
$form_state['view']->set_item($form_state['display_id'], $form_state['type'], $form_state['id'], $item);
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;
2403
* Form to config_item items in the views UI.
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'];
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)));
2415
$item = $view->get_item($display_id, $type, $id);
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'])));
2424
$handler->init($view, $item);
2425
$types = views_object_types();
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()));
2430
$form['#section'] = $display_id . '-' . $type . '-' . $id;
2432
// Get form from the handler.
2433
$handler->extra_options_form($form['options'], $form_state);
2434
$form_state['handler'] = &$handler;
2438
views_ui_standard_form_buttons($form, $form_state, 'views_ui_config_item_extra_form');
2444
* Submit handler for configing new item(s) to a view.
2446
function views_ui_config_item_extra_form_validate($form, &$form_state) {
2447
$form_state['handler']->extra_options_validate($form['options'], $form_state);
2451
* Submit handler for configing new item(s) to a view.
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;
2458
// Store the data we're given.
2459
foreach ($form_state['values']['options'] as $key => $value) {
2460
$item[$key] = $value;
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);
2467
views_ui_cache_set($form_state['view']);
2471
* Form to change_style items in the views UI.
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'];
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)));
2483
$item = $view->get_item($display_id, $type, $id);
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'])));
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()));
2495
$form['#section'] = $display_id . '-' . $type . '-' . $id . '-style-plugin';
2497
$form['style_plugin'] = array(
2498
'#type' => 'radios',
2499
'#options' => views_fetch_plugin_names('style', 'summary'),
2500
'#default_value' => $item['style_plugin'],
2503
$form_state['handler'] = &$handler;
2505
views_ui_standard_form_buttons($form, $form_state, 'views_ui_change_style_form');
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);
2514
$plugin = views_get_plugin('style', $form_state['values']['style_plugin']);
2516
form_error($form['style_plugin'], t('Internal error: broken plugin.'));
2521
* Submit handler for configing new item(s) to a view.
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;
2528
$plugin = views_get_plugin('style', $form_state['values']['style_plugin']);
2530
drupal_set_message(t('Internal error: broken plugin.'), 'error');
2534
$plugin->init($form_state['view'], $form_state['view']->display[$form_state['display_id']]);
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;
2541
// Store the data we're given.
2542
$item['style_plugin'] = $form_state['values']['style_plugin'];
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);
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);
2552
views_ui_cache_set($form_state['view']);
2556
* Form to config_style items in the views UI.
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'];
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)));
2568
$item = $view->get_item($display_id, $type, $id);
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'])));
2576
$handler->init($view, $item);
2577
$types = views_object_types();
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()));
2582
$form['#section'] = $display_id . '-' . $type . '-style-options';
2584
$plugin = views_get_plugin('style', $item['style_plugin']);
2586
$form['style_options'] = array(
2589
$plugin->init($view, $view->display[$display_id], $item['style_options']);
2591
$plugin->options_form($form['style_options'], $form_state);
2594
$form_state['handler'] = &$handler;
2596
views_ui_standard_form_buttons($form, $form_state, 'views_ui_config_style_form');
2602
* Submit handler for configing new item(s) to a view.
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;
2609
// Store the data we're given.
2610
$item['style_options'] = $form_state['values']['style_options'];
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);
2616
views_ui_cache_set($form_state['view']);
2620
* Get a list of roles in the system.
2622
function views_ui_get_roles() {
2623
static $roles = NULL;
2624
if (!isset($roles)) {
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;
2636
* Get a css safe id for a particular section.
2638
function views_ui_item_css($item) {
2639
return views_css_safe('views-item-' . $item);
2643
* Page callback for the Views enable page.
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();
2651
drupal_goto('admin/build/views');
2655
* Page callback for the Views enable page
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();
2663
drupal_goto('admin/build/views');
2667
* Page callback for the tools - other page
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'),
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),
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),
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),
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),
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),
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),
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),
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),
2732
$regions = system_region_list(variable_get('theme_default', 'garland'));
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,
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'),
2748
return system_settings_form($form);
2752
* Submit hook to clear the views cache.
2754
function views_ui_tools_clear_cache() {
2755
views_invalidate_cache();
2756
drupal_set_message(t('The cache has been cleared.'));
2760
* Submit hook to clear Drupal's theme registry (thereby triggering
2761
* a templates rescan).
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();
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']);
2777
$form_state['rerender'] = TRUE;
2778
$form_state['rebuild'] = TRUE;
2782
* Page callback for views tag autocomplete
2784
function views_ui_autocomplete_tag($string = '') {
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;
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);
2802
drupal_json($matches);
2805
// ------------------------------------------------------------------
2806
// Get information from the Views data
2808
function _views_weight_sort($a, $b) {
2809
if ($a['weight'] != $b['weight']) {
2810
return $a['weight'] < $b['weight'] ? -1 : 1;
2812
if ($a['title'] != $b['title']) {
2813
return $a['title'] < $b['title'] ? -1 : 1;
2820
* Fetch a list of all base tables available
2823
* A keyed array of in the form of 'base_table' => 'Description'.
2825
function views_fetch_base_tables() {
2826
static $base_tables = array();
2827
if (empty($base_tables)) {
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,
2840
uasort($tables, '_views_weight_sort');
2841
$base_tables = $tables;
2844
return $base_tables;
2847
function _views_sort_types($a, $b) {
2848
if ($a['group'] != $b['group']) {
2849
return $a['group'] < $b['group'] ? -1 : 1;
2852
if ($a['title'] != $b['title']) {
2853
return $a['title'] < $b['title'] ? -1 : 1;
2860
* Fetch a list of all fields available for a given base type.
2863
* A keyed array of in the form of 'base_table' => 'Description'.
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'.
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.
2880
foreach ($data as $table => $table_data) {
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']);
2891
// And it obviously joins to itself.
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;
2902
elseif (!empty($info['skip base'])) {
2903
foreach ((array) $info['skip base'] as $base_name) {
2904
$skip_bases[$field][$key][$base_name] = TRUE;
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];
2912
// Then try the field level
2913
elseif (!empty($info[$string])) {
2914
$strings[$field][$key][$string] = $info[$string];
2916
// Finally, try the table level
2917
elseif (!empty($table_data['table'][$string])) {
2918
$strings[$field][$key][$string] = $table_data['table'][$string];
2921
if ($string != 'base') {
2922
$strings[$field][$key][$string] = t("Error: missing @component", array('@component' => $string));
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;
2939
// vsm('Views UI data build time: ' . (views_microtime() - $start) * 1000 . ' ms');
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
2945
if (is_array($base)) {
2947
foreach ($base as $base_table) {
2948
if (isset($fields[$base_table][$type])) {
2949
$strings += $fields[$base_table][$type];
2952
uasort($strings, '_views_sort_types');
2956
if (isset($fields[$base][$type])) {
2957
uasort($fields[$base][$type], '_views_sort_types');
2958
return $fields[$base][$type];
2964
* Fetch a list of all base tables available
2967
* Either 'display', 'style' or 'row'
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.
2972
* An array of possible base tables.
2975
* A keyed array of in the form of 'base_table' => 'Description'.
2977
function views_fetch_plugin_names($type, $key = NULL, $base = array()) {
2978
$data = views_fetch_plugin_data();
2980
$plugins[$type] = array();
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)) {
2987
if (empty($plugin['no ui']) && (empty($base) || empty($plugin['base']) || array_intersect($base, $plugin['base']))) {
2988
$plugins[$type][$id] = $plugin['title'];
2992
if (!empty($plugins[$type])) {
2993
asort($plugins[$type]);
2994
return $plugins[$type];
3002
* Theme the form for the table style plugin
3004
function theme_views_ui_style_plugin_table($form) {
3005
$output = drupal_render($form['description_markup']);
3012
'data' => t('Sortable'),
3013
'align' => 'center',
3016
'data' => t('Default sort'),
3017
'align' => 'center',
3021
foreach (element_children($form['columns']) as $id) {
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'])) {
3028
'data' => drupal_render($form['info'][$id]['sortable']),
3029
'align' => 'center',
3032
'data' => drupal_render($form['default'][$id]),
3033
'align' => 'center',
3043
// Add the special 'None' row.
3044
$rows[] = array(t('None'), '', '', '', array('align' => 'center', 'data' => drupal_render($form['default'][-1])));
3046
$output .= theme('table', $header, $rows);
3047
$output .= drupal_render($form);