/[drupal]/contributions/modules/views/includes/admin.inc
ViewVC logotype

Contents of /contributions/modules/views/includes/admin.inc

Parent Directory Parent Directory | Revision Log Revision Log | View Revision Graph Revision Graph


Revision 1.161 - (show annotations) (download) (as text)
Tue Sep 15 16:47:12 2009 UTC (2 months, 1 week ago) by merlinofchaos
Branch: MAIN
CVS Tags: HEAD
Branch point for: DRUPAL-6--2, DRUPAL-7--3
Changes since 1.160: +2 -2 lines
File MIME type: text/x-php
#511468 by dereine: State which view was saved after saving a view.
1 <?php
2 // $Id: admin.inc,v 1.160 2009/06/10 22:01:31 merlinofchaos Exp $
3 /**
4 * @file admin.inc
5 * Provides the Views' administrative interface.
6 */
7
8 /**
9 * Page callback to list views in the system.
10 */
11 function views_ui_list_views($arg = NULL) {
12 if ($arg != NULL) {
13 return drupal_not_found();
14 }
15
16 $output = theme('views_ui_list_views');
17 views_ui_check_advanced_help();
18 return $output;
19 }
20
21 /**
22 * Check to see if the advanced help module is installed, and if not put up
23 * a message.
24 *
25 * Only call this function if the user is already in a position for this to
26 * be useful.
27 */
28 function views_ui_check_advanced_help() {
29 if (variable_get('views_hide_help_message', FALSE)) {
30 return;
31 }
32
33 if (!module_exists('advanced_help')) {
34 $filename = db_result(db_query("SELECT filename FROM {system} WHERE type = 'module' AND name = 'advanced_help'"));
35 if ($filename && file_exists($filename)) {
36 drupal_set_message(t('If you <a href="@modules">enable the advanced help module</a>, Views will provide more and better help. <a href="@hide">Hide this message.</a>', array('@modules' => url('admin/build/modules'),'@hide' => url('admin/build/views/tools'))));
37 }
38 else {
39 drupal_set_message(t('If you install the advanced help module from !href, Views will provide more and better help. <a href="@hide">Hide this message.</a>', array('!href' => l('http://drupal.org/project/advanced_help', 'http://drupal.org/project/advanced_help'), '@hide' => url('admin/build/views/tools'))));
40 }
41 }
42 }
43
44 /**
45 * Preprocess the list views theme
46 */
47 function template_preprocess_views_ui_list_views(&$vars) {
48 $items = array();
49 $sorts = array();
50
51 $views = views_get_all_views();
52
53 // Respond to a reset command by clearing session and doing a drupal goto
54 // back to the base URL.
55 if (isset($_GET['op']) && $_GET['op'] == t('Reset')) {
56 unset($_SESSION['views']['#admin']);
57 drupal_goto('admin/build/views');
58 }
59 if (count($_GET) <= 1) {
60 if (isset($_SESSION['views']['#admin']) && is_array($_SESSION['views']['#admin'])) {
61 $_GET += $_SESSION['views']['#admin'];
62 }
63 }
64 else {
65 $_SESSION['views']['#admin'] = $_GET;
66 unset($_SESSION['views']['#admin']['q']);
67 }
68
69 $form_state = array(
70 'views' => $views,
71 'input' => $_GET,
72 'method' => 'get',
73 'rerender' => TRUE,
74 'no_redirect' => TRUE,
75 );
76
77 $vars['widgets'] = drupal_build_form('views_ui_list_views_form', $form_state);
78
79 $vars['help_type_icon'] = theme('advanced_help_topic', 'views', 'view-type');
80
81 $base_tables = views_fetch_base_tables();
82
83 foreach ($views as $view) {
84 if ($form_state['values']['tag'] != 'all') {
85 if ($form_state['values']['tag'] == 'none') {
86 if (!empty($view->tag)) {
87 continue;
88 }
89 }
90 else if ($form_state['values']['tag'] != $view->tag) {
91 continue;
92 }
93 }
94 if ($form_state['values']['type'] != 'all' && $form_state['values']['type'] != $view->type) {
95 continue;
96 }
97
98 if ($form_state['values']['base'] != 'all' && $form_state['values']['base'] != $view->base_table) {
99 continue;
100 }
101
102 if ($form_state['values']['display'] != 'all' && empty($view->display[$form_state['values']['display']])) {
103 continue;
104 }
105
106 $item = new stdClass();
107 $item->ops = array();
108 if (empty($view->disabled)) {
109 $item->ops[] = l(t('Edit'), "admin/build/views/edit/$view->name");
110 $item->ops[] = l(t('Export'), "admin/build/views/export/$view->name");
111 $item->ops[] = l(t('Clone'), "admin/build/views/clone/$view->name");
112 }
113 if ($view->type != t('Default')) {
114 $text = $view->type == t('Overridden') ? t('Revert') : t('Delete');
115 $item->ops[] = l($text, "admin/build/views/delete/$view->name");
116 }
117 else {
118 if (empty($view->disabled)) {
119 $item->ops[] = l(t('Disable'), "admin/build/views/disable/$view->name", array('query' => drupal_get_destination()));
120 }
121 else {
122 $item->ops[] = l(t('Enable'), "admin/build/views/enable/$view->name", array('query' => drupal_get_destination()));
123 }
124 }
125
126 $item->ops = implode(' | ', $item->ops);
127 if (empty($view->display)) {
128 $item->path = t('Warning! Broken view!');
129 }
130 else {
131 $item->path = $raw_path = $view->get_path();
132 $item->path = $item->path && empty($view->disabled) && strpos($item->path, '%') === FALSE ? l($item->path, $item->path) : check_plain($item->path);
133 }
134
135 $item->type = $view->type;
136 $item->name = $view->name;
137
138 if (!empty($view->tag)) {
139 $item->tag = $view->tag;
140 }
141
142 $item->title = $view->get_title();
143 $item->base = !empty($base_tables[$view->base_table]['title']) ? $base_tables[$view->base_table]['title'] : t('Broken');
144
145 $item->displays = array();
146 foreach ($view->display as $display) {
147 if (!empty($display->handler->definition['admin'])) {
148 $item->displays[$display->handler->definition['admin']] = TRUE;
149 }
150 }
151
152 if ($item->displays) {
153 ksort($item->displays);
154 $item->displays = implode(', ', array_keys($item->displays));
155 }
156
157 $item->description = check_plain($view->description);
158 $item->classes = empty($view->disabled) ? 'view-enabled' : 'view-disabled';
159 $items[] = $item;
160
161 $sort = intval(empty($view->disabled) xor $form_state['values']['sort'] == 'asc');
162
163 switch ($form_state['values']['order']) {
164 case 'name':
165 default:
166 $sort .= strtolower($view->name);
167 break;
168 case 'title':
169 $sort .= strtolower($item->title);
170 break;
171 case 'path':
172 $sort .= strtolower($raw_path); // $path;
173 break;
174 case 'type':
175 $sort .= $view->type . $view->name;
176 break;
177 case 'tag':
178 $sort .= strtolower($view->tag);
179 break;
180 case 'desc':
181 $sort .= strtolower($view->description);
182 break;
183 }
184
185 $sorts[] = $sort;
186 }
187
188 if ($form_state['values']['sort'] == 'desc') {
189 arsort($sorts);
190 }
191 else {
192 asort($sorts);
193 }
194
195 $i = array();
196 foreach ($sorts as $id => $title) {
197 $i[] = $items[$id];
198 }
199
200 views_add_css('views-list');
201 $vars['views'] = $i;
202
203 $getting_started = theme('advanced_help_topic', 'views', 'getting-started', 'title');
204 if (!$getting_started) {
205 $getting_started = t('Install the advanced help module for the getting started');
206 }
207
208 $vars['help'] = t('Not sure what to do? Try the "!getting-started" page.', array('!getting-started' => $getting_started));
209 }
210
211 /**
212 * Provide a form for sorting and filtering the list of views.
213 */
214 function views_ui_list_views_form(&$form_state) {
215 if (!variable_get('clean_url', FALSE)) {
216 $form['q'] = array(
217 '#type' => 'hidden',
218 '#value' => $_GET['q'],
219 );
220 }
221
222 $all = array('all' => t('<All>'));
223 $none = array('none' => t('<None>'));
224
225 $form['type'] = array(
226 '#type' => 'select',
227 '#title' => t('Storage'),
228 '#options' => array(
229 'all' => t('<All>'),
230 t('Normal') => t('Normal'),
231 t('Default') => t('Default'),
232 t('Overridden') => t('Overridden'),
233 ),
234 '#default_value' => 'all',
235 );
236
237 $bases = array();
238 foreach (views_fetch_base_tables() as $table => $info) {
239 $bases[$table] = $info['title'];
240 }
241
242 $form['base'] = array(
243 '#type' => 'select',
244 '#title' => t('Type'),
245 '#options' => array_merge($all, $bases),
246 '#default_value' => 'all',
247 );
248
249 $tags = array();
250
251 $extras = array();
252 foreach ($form_state['views'] as $name => $view) {
253 if (!empty($view->tag)) {
254 $tags[$view->tag] = $view->tag;
255 }
256 }
257
258 asort($tags);
259
260 $form['tag'] = array(
261 '#type' => 'select',
262 '#title' => t('Tag'),
263 '#options' => array_merge($all, $none, $tags),
264 '#default_value' => 'all',
265 );
266
267 $displays = array();
268 foreach (views_fetch_plugin_data('display') as $id => $info) {
269 if (!empty($info['admin'])) {
270 $displays[$id] = $info['admin'];
271 }
272 }
273
274 asort($displays);
275
276 $form['display'] = array(
277 '#type' => 'select',
278 '#title' => t('Displays'),
279 '#options' => array_merge($all, $displays),
280 '#default_value' => 'all',
281 );
282
283 $form['order'] = array(
284 '#type' => 'select',
285 '#title' => t('Sort by'),
286 '#options' => array(
287 'name' => t('Name'),
288 'title' => t('Title'),
289 'tag' => t('Tag'),
290 'path' => t('Path'),
291 'type' => t('Type'),
292 'desc' => t('Description'),
293 ),
294 '#default_value' => 'name',
295 );
296
297 $form['sort'] = array(
298 '#type' => 'select',
299 '#title' => t('Order'),
300 '#options' => array(
301 'asc' => t('Up'),
302 'desc' => t('Down'),
303 ),
304 '#default_value' => 'asc',
305 );
306
307 $form['submit'] = array(
308 '#name' => '', // so it won't in the $_GET args
309 '#type' => 'submit',
310 '#id' => 'edit-views-apply',
311 '#value' => t('Apply'),
312 );
313
314 if (!empty($_SESSION['views']['#admin'])) {
315 $form['reset'] = array(
316 '#type' => 'submit',
317 '#id' => 'edit-views-reset',
318 '#value' => t('Reset'),
319 );
320 }
321
322 $form['#theme'] = array('views_ui_list_views_form');
323 return $form;
324 }
325
326 function theme_views_ui_list_views_form($form) {
327 // Don't render these:
328 unset($form['form_id']);
329 unset($form['form_build_id']);
330 unset($form['form_token']);
331 return drupal_render($form);
332 }
333
334 /**
335 * Page callback for the live preview.
336 *
337 * @todo make this use a template
338 */
339 function views_ui_preview($js, $view) {
340 // Take off the items we know so that we can have just the args passed
341 // in for later use.
342 $func_args = func_get_args();
343 array_shift($func_args); // $js
344 array_shift($func_args); // $view
345 $display_id = (count($func_args)) ? array_shift($func_args) : 'default';
346
347 $form_state = array(
348 'display_id' => $display_id,
349 'view_args' => $func_args ? implode('/', $func_args) : '',
350 'rerender' => TRUE,
351 'no_redirect' => TRUE,
352 'view' => &$view,
353 'ajax' => $js
354 );
355
356 $output = drupal_build_form('views_ui_preview_form', $form_state);
357 $args = array();
358 if (isset($form_state['view_args']) && $form_state['view_args'] !== '') {
359 $args = explode('/', $form_state['view_args']);
360 }
361
362 $errors = $view->validate();
363 if ($errors === TRUE) {
364 $view->ajax = $js;
365 $view->live_preview = TRUE;
366
367 // Store the current view URL for later use:
368 $view->set_display($form_state['display_id']);
369 $view->set_arguments($args);
370
371 if ($view->display_handler->get_option('path')) {
372 $path = $view->get_url();
373 }
374
375 // Make view links come back to preview.
376 $view->override_path = 'admin/build/views/nojs/preview/' . $view->name . '/' . $form_state['display_id'];
377
378 // also override $_GET['q'] so we get the pager
379 $_GET['q'] = $view->override_path;
380 if ($form_state['view_args']) {
381 $_GET['q'] .= '/' . $form_state['view_args'];
382 }
383
384 $preview = $view->preview($form_state['display_id'], $args);
385
386 // Get information from the preview for display.
387 if (!empty($view->build_info['query'])) {
388 $rows = array();
389 $query = db_prefix_tables($view->build_info['query']);
390 if ($view->build_info['query_args']) {
391 _db_query_callback($view->build_info['query_args'], TRUE);
392 $query = preg_replace_callback(DB_QUERY_REGEXP, '_db_query_callback', $query);
393 }
394 $rows[] = array('<strong>' . t('Query') . '</strong>', '<pre>' . check_plain($query) . '</pre>');
395 if (!empty($view->additional_queries)) {
396 $queries = '<strong>' . t('These queries were run during view rendering:') . '</strong>';
397 foreach ($view->additional_queries as $query) {
398 if ($queries) {
399 $queries .= "\n";
400 }
401 $queries .= t('[@time ms]', array('@time' => intval($query[1] * 100000) / 100)) . ' ' . $query[0];
402 }
403
404 $rows[] = array('<strong>' . t('Other queries') . '</strong>', '<pre>' . $queries . '</pre>');
405 }
406
407 $rows[] = array('<strong>' . t('Title') . '</strong>', filter_xss_admin($view->get_title()));
408 if (isset($path)) {
409 $path = l($path, $path);
410 }
411 else {
412 $path = t('This display has no path.');
413 }
414
415 $rows[] = array('<strong>' . t('Path') . '</strong>', $path);
416
417 $rows[] = array('<strong>' . t('Query build time') . '</strong>', t('@time ms', array('@time' => intval($view->build_time * 100000) / 100)));
418 $rows[] = array('<strong>' . t('Query execute time') . '</strong>', t('@time ms', array('@time' => intval($view->execute_time * 100000) / 100)));
419 $rows[] = array('<strong>' . t('View render time') . '</strong>', t('@time ms', array('@time' => intval($view->render_time * 100000) / 100)));
420 drupal_alter('views_preview_info', $rows, $view);
421
422 $info = theme('table', array(), $rows);
423 }
424 else {
425 $info = theme('table', array(), array(array('<strong>' . t('Query') . '</strong>', t('No query was run'))));
426 }
427 }
428 else {
429 foreach ($errors as $error) {
430 drupal_set_message($error, 'error');
431 }
432 $preview = t('Unable to preview due to validation errors.');
433 $info = '';
434 }
435
436 $info = '<div class="views-query-info">' . $info . '</div>';
437
438 if (variable_get('views_ui_query_on_top', FALSE)) {
439 $output .= $info . $preview;
440 }
441 else {
442 $output .= $preview . $info;
443 }
444
445 if (!$js) {
446 views_add_css('views-admin');
447 drupal_set_title($view->get_title());
448 return $output;
449 }
450 else {
451 views_include('ajax');
452 $object = new stdClass();
453 if (!empty($view->js_settings)) {
454 $object->js = $view->js_settings;
455 }
456 $object->display = '';
457 if ($messages = theme('status_messages')) {
458 $object->display = '<div class="views-messages">' . $messages . '</div>';
459 }
460 $object->display .= $output;
461 $object->title = $view->get_title();
462 views_ajax_render($object);
463 }
464 }
465
466 /**
467 * Form for generating argument information for the live preview.
468 */
469 function views_ui_preview_form(&$form_state) {
470 $view = &$form_state['view'];
471 $view->init_display();
472 $options = array();
473 foreach ($view->display as $id => $display) {
474 $options[$id] = $display->display_title;
475 }
476
477 $form['#attributes'] = array(
478 'class' => 'clear-block',
479 );
480
481 $form['display_id'] = array(
482 '#type' => 'select',
483 '#title' => t('Display'),
484 '#options' => $options,
485 '#default_value' => $form_state['display_id'],
486 '#id' => 'preview-display-id',
487 );
488
489 $form['args'] = array(
490 '#type' => 'textfield',
491 '#title' => t('Arguments'),
492 '#default_value' => $form_state['view_args'],
493 '#description' => t('Separate arguments with a / as though they were a URL path.'),
494 '#id' => 'preview-args',
495 );
496
497 $form['preview'] = array(
498 '#type' => 'submit',
499 '#value' => t('Preview'),
500 '#id' => 'preview-submit',
501 );
502
503 $form['#action'] = url("admin/build/views/nojs/preview/$view->name");
504 return $form;
505 }
506
507 /**
508 * Submit the preview form.
509 *
510 * This just takes the data and stores it on the form state in a
511 * known location. The caller will be responsible for using it.
512 */
513 function views_ui_preview_form_submit(&$form, &$form_state) {
514 $form_state['display_id'] = $form_state['values']['display_id'];
515 $form_state['view_args'] = $form_state['values']['args'];
516 }
517
518 /**
519 * Page callback to add a new view.
520 */
521 function views_ui_add_page() {
522 $form_state = array(
523 'view' => NULL
524 );
525
526 return drupal_build_form('views_ui_add_form', $form_state);
527 }
528
529 /**
530 * Page callback to add a new view.
531 */
532 function views_ui_clone_page($view) {
533 $form_state = array(
534 'view' => $view->copy(),
535 );
536
537 drupal_set_title(t('Clone view %view', array('%view' => $view->name)));
538 return drupal_build_form('views_ui_add_form', $form_state);
539 }
540
541 /**
542 * Form constructor callback to create the views Add Form, phase 1.
543 */
544 function views_ui_add_form(&$form_state) {
545 $view = $form_state['view'];
546 $form = array();
547
548 $form['name'] = array(
549 '#type' => 'textfield',
550 '#title' => t('View name'),
551 '#description' => t('This is the unique name of the view. It must contain only alphanumeric characters and underscores; it is used to identify the view internally and to generate unique theming template names for this view. If overriding a module provided view, the name must not be changed or instead a new view will be created.'),
552 '#required' => TRUE,
553 '#maxlength' => 32,
554 '#default_value' => $view ? $view->name : '',
555 '#attributes' => array('dir'=>'ltr'),
556 );
557
558 $form['description'] = array(
559 '#type' => 'textfield',
560 '#title' => t('View description'),
561 '#description' => t('This description will appear on the Views administrative UI to tell you what the view is about.'),
562 '#default_value' => $view ? $view->description : '',
563 );
564
565 $form['tag'] = array(
566 '#type' => 'textfield',
567 '#title' => t('View tag'),
568 '#description' => t('Enter an optional tag for this view; it is used only to help sort views on the administrative page.'),
569 '#default_value' => $view ? $view->tag : '',
570 '#autocomplete_path' => 'admin/views/ajax/autocomplete/tag',
571 );
572
573 $base_tables = array();
574 foreach (views_fetch_base_tables() as $table => $info) {
575 $base_tables[$table] = $info['title'] . '<div class="description">' . $info['description'] . '</div>';
576 }
577
578 $form['base_table'] = array(
579 '#type' => 'radios',
580 '#title' => t('View type'),
581 '#description' => t('The view type is the primary table for which information is being retrieved. The view type controls what arguments, fields, sort criteria and filters are available, so once this is set it <strong>cannot be changed</strong>.'),
582 '#default_value' => $view ? $view->base_table : 'node',
583 '#options' => $base_tables,
584 );
585
586 if ($view) {
587 $form['base_table']['#disabled'] = TRUE;
588 }
589
590 $form['submit'] = array(
591 '#type' => 'submit',
592 '#value' => t('Next'),
593 '#validate' => array('views_ui_add_form_validate'),
594 '#submit' => array('views_ui_add_form_submit'),
595 );
596
597 return $form;
598 }
599
600 /**
601 * Validate the add view form.
602 */
603 function views_ui_add_form_validate($form, &$form_state) {
604 $name = $form_state['values']['name'];
605
606 // View name must be alphanumeric or underscores, no other punctuation.
607 if (preg_match('/[^a-zA-Z0-9_]/', $name)) {
608 form_error($form['name'], t('View name must be alphanumeric or underscores only.'));
609 }
610
611 // View name must already exist.
612 $view = views_get_view($form_state['values']['name']);
613 if ($view && $view->type != t('Default')) {
614 form_error($form['name'], t('You must use a unique name for this view.'));
615 }
616 }
617
618 /**
619 * Process the add view form
620 */
621 function views_ui_add_form_submit($form, &$form_state) {
622 $view = $form_state['view'] ? $form_state['view'] : views_new_view();
623 $view->name = $form_state['values']['name'];
624 $view->description = $form_state['values']['description'];
625 $view->tag = $form_state['values']['tag'];
626 if (empty($form['base_table']['#disabled'])) {
627 $view->base_table = $form_state['values']['base_table'];
628 }
629
630 views_ui_cache_set($view);
631 $form_state['redirect'] ='admin/build/views/edit/' . $view->name;
632 }
633
634 /**
635 * Page to delete a view.
636 */
637 function views_ui_delete_confirm(&$form_state, $view) {
638 $form_state['view'] = &$view;
639 $form = array();
640
641 $cancel = 'admin/build/views';
642 if (!empty($_REQUEST['cancel'])) {
643 $cancel = $_REQUEST['cancel'];
644 }
645
646 if ($view->type == t('Overridden')) {
647 $title = t('Are you sure you want to revert the view %name?', array('%name' => $view->name));
648 $desc = t('Reverting the view will delete the view that is in the database, reverting it to the original default view. Any changes you have made will be lost and cannot be recovered.');
649 $button = t('Revert');
650 }
651 else {
652 $title = t('Are you sure you want to delete the view %name?', array('%name' => $view->name));
653 $desc = t('Deleting a view cannot be undone.');
654 $button = t('Delete');
655 }
656
657 return confirm_form($form,
658 $title,
659 $cancel,
660 $desc,
661 $button,
662 t('Cancel'));
663 }
664
665 /**
666 * Submit handler to delete a view.
667 */
668 function views_ui_delete_confirm_submit(&$form, &$form_state) {
669 $form_state['view']->delete();
670 views_object_cache_clear('view', $form_state['view']->name);
671 drupal_set_message(t('The view has been deleted.'));
672 $form_state['redirect'] = 'admin/build/views';
673 }
674
675 /**
676 * Page to delete a view.
677 */
678 function views_ui_break_lock_confirm(&$form_state, $view) {
679 $form_state['view'] = &$view;
680 $form = array();
681
682 if (empty($view->locked)) {
683 return t('There is no lock on view %view to break.', array('%name' => $view->name));
684 }
685
686 $cancel = 'admin/build/views/edit/' . $view->name;
687 if (!empty($_REQUEST['cancel'])) {
688 $cancel = $_REQUEST['cancel'];
689 }
690
691 $account = user_load($view->locked->uid);
692 return confirm_form($form,
693 t('Are you sure you want to break the lock on view %name?',
694 array('%name' => $view->name)),
695 $cancel,
696 t('By breaking this lock, any unsaved changes made by !user will be lost!', array('!user' => theme('username', $account))),
697 t('Break lock'),
698 t('Cancel'));
699 }
700
701 /**
702 * Submit handler to break_lock a view.
703 */
704 function views_ui_break_lock_confirm_submit(&$form, &$form_state) {
705 db_query("DELETE FROM {views_object_cache} WHERE obj = 'view' AND name = '%s'", $form_state['view']->name);
706 $form_state['redirect'] = 'admin/build/views/edit/' . $form_state['view']->name;
707 drupal_set_message(t('The lock has been broken and you may now edit this view.'));
708 }
709
710 /**
711 * The main view edit page
712 */
713 function views_ui_edit_page($view) {
714 drupal_set_title(t('Edit view %view', array('%view' => $view->name)));
715 $output = theme('views_ui_edit_view', $view);
716 views_ui_check_advanced_help();
717 return $output;
718 }
719
720 /**
721 * Export a view for cut & paste.
722 */
723 function views_ui_export_page(&$form_state, $view) {
724 $code = $view->export();
725 $lines = substr_count($code, "\n");
726 $form['code'] = array(
727 '#type' => 'textarea',
728 '#title' => $view->name,
729 '#default_value' => $code,
730 '#rows' => $lines,
731 );
732 return $form;
733 }
734
735 /**
736 * Import a view from cut & paste
737 */
738 function views_ui_import_page(&$form_state) {
739 $form['name'] = array(
740 '#type' => 'textfield',
741 '#title' => t('View name'),
742 '#description' => t('Enter the name to use for this view if it is different from the source view. Leave blank to use the name of the view.'),
743 );
744
745 $form['view'] = array(
746 '#type' => 'textarea',
747 '#title' => t('Paste view code here'),
748 '#required' => TRUE,
749 );
750
751 $form['submit'] = array(
752 '#type' => 'submit',
753 '#value' => t('Import'),
754 '#submit' => array('views_ui_import_submit'),
755 '#validate' => array('views_ui_import_validate'),
756 );
757 return $form;
758 }
759
760 /**
761 * Validate handler to import a view
762 */
763 function views_ui_import_validate($form, &$form_state) {
764 $view = '';
765 views_include('view');
766 ob_start();
767 eval($form_state['values']['view']);
768 ob_end_clean();
769
770 if (!is_object($view)) {
771 return form_error($form['view'], t('Unable to interpret view code.'));
772 }
773
774 if (empty($view->api_version) || $view->api_version < 2) {
775 // Check for some value that would only exist on a Views 1 view.
776 if (isset($view->url) || isset($view->page) || isset($view->block)) {
777 views_include('convert');
778 $view = views1_import($view);
779 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 }
781 else {
782 form_error($form['view'], t('That view is not compatible with this version of Views.'));
783 }
784 }
785
786 // View name must be alphanumeric or underscores, no other punctuation.
787 if (!empty($form_state['values']['name']) && preg_match('/[^a-zA-Z0-9_]/', $form_state['values']['name'])) {
788 form_error($form['name'], t('View name must be alphanumeric or underscores only.'));
789 }
790
791 if ($form_state['values']['name']) {
792 $view->name = $form_state['values']['name'];
793 }
794
795 $test = views_get_view($view->name);
796 if ($test && $test->type != t('Default')) {
797 form_set_error('', t('A view by that name already exists; please choose a different name'));
798 }
799
800 $view->init_display();
801
802 $broken = FALSE;
803 // Make sure that all plugins and handlers needed by this view actually exist.
804 foreach ($view->display as $id => $display) {
805 if (empty($display->handler) || !empty($display->handler->broken)) {
806 drupal_set_message(t('Display plugin @plugin is not available.', array('@plugin' => $display->display_plugin)), 'error');
807 $broken = TRUE;
808 continue;
809 }
810
811 $plugin = views_get_plugin('style', $display->handler->get_option('style_plugin'));
812 if (!$plugin) {
813 drupal_set_message(t('Style plugin @plugin is not available.', array('@plugin' => $display->handler->get_option('style_plugin'))), 'error');
814 $broken = TRUE;
815 }
816 else if ($plugin->uses_row_plugin()) {
817 $plugin = views_get_plugin('row', $display->handler->get_option('row_plugin'));
818 if (!$plugin) {
819 drupal_set_message(t('Row plugin @plugin is not available.', array('@plugin' => $display->handler->get_option('row_plugin'))), 'error');
820 $broken = TRUE;
821 }
822 }
823
824 foreach (views_object_types() as $type => $info) {
825 $handlers = $display->handler->get_handlers($type);
826 if ($handlers) {
827 foreach ($handlers as $id => $handler) {
828 if ($handler->broken()) {
829 drupal_set_message(t('@type handler @table.@field is not available.', array(
830 '@type' => $info['stitle'],
831 '@table' => $handler->table,
832 '@field' => $handler->field,
833 )), 'error');
834 $broken = TRUE;
835 }
836 }
837 }
838 }
839 }
840
841 if ($broken) {
842 form_set_error('', t('Unable to import view.'));
843 }
844
845 $form_state['view'] = &$view;
846 }
847
848 /**
849 * Submit handler for view import
850 */
851 function views_ui_import_submit($form, &$form_state) {
852 // Store in cache and then go to edit.
853 views_ui_cache_set($form_state['view']);
854 $form_state['redirect'] = 'admin/build/views/edit/' . $form_state['view']->name;
855 }
856
857 /**
858 * The main edit view form, which is really just a save/cancel/delete button.
859 */
860 function views_ui_edit_view_form(&$form_state, $view) {
861 $form['buttons']['save'] = array(
862 '#type' => 'submit',
863 '#value' => t('Save'),
864 '#validate' => array('views_ui_edit_view_form_validate'),
865 '#submit' => array('views_ui_edit_view_form_submit'),
866 );
867
868 $form['buttons']['cancel'] = array(
869 '#type' => 'submit',
870 '#value' => t('Cancel'),
871 '#submit' => array('views_ui_edit_view_form_cancel'),
872 );
873
874 if (is_numeric($view->vid)) {
875 $form['buttons']['delete'] = array(
876 '#type' => 'submit',
877 '#value' => t('Delete'),
878 '#submit' => array('views_ui_edit_view_form_delete'),
879 );
880 }
881
882 $form_state['view'] = &$view;
883 return $form;
884 }
885
886 /**
887 * Validate that a view is complete and whole.
888 */
889 function views_ui_edit_view_form_validate($form, &$form_state) {
890 // Do not validate cancel or delete.
891 if (empty($form_state['clicked_button']['#value']) || $form_state['clicked_button']['#value'] != t('Save')) {
892 return;
893 }
894
895 $errors = $form_state['view']->validate();
896 if ($errors !== TRUE) {
897 foreach ($errors as $error) {
898 form_set_error('', $error);
899 }
900 }
901 }
902
903 /**
904 * Submit handler for the edit view form.
905 */
906 function views_ui_edit_view_form_submit($form, &$form_state) {
907 // Go through and remove displayed scheduled for removal.
908 foreach ($form_state['view']->display as $id => $display) {
909 if (!empty($display->deleted)) {
910 unset($form_state['view']->display[$id]);
911 }
912 }
913
914 $form_state['view']->save();
915 drupal_set_message(t('The view %name has been saved.', array('%name' => $form_state['view']->name)));
916
917 // Make sure menu items get rebuilt as neces
918 menu_rebuild();
919
920 // Clear the views cache.
921 cache_clear_all('*', 'cache_views');
922
923 // Clear the page cache.
924 cache_clear_all();
925
926 // Remove this view from cache so we can edit it properly.
927 views_object_cache_clear('view', $form_state['view']->name);
928 }
929
930 /**
931 * Submit handler for the edit view form.
932 */
933 function views_ui_edit_view_form_cancel($form, &$form_state) {
934 // Remove this view from cache so edits will be lost.
935 views_object_cache_clear('view', $form_state['view']->name);
936 if (empty($form['view']->vid)) {
937 // I seem to have to drupal_goto here because I can't get fapi to
938 // honor the redirect target. Not sure what I screwed up here.
939 drupal_goto('admin/build/views');
940 }
941 }
942
943 function views_ui_edit_view_form_delete($form, &$form_state) {
944 unset($_REQUEST['destination']);
945 // Redirect to the delete confirm page
946 $form_state['redirect'] = array('admin/build/views/delete/' . $form_state['view']->name, 'cancel=admin/build/views/edit/' . $form_state['view']->name);
947 }
948
949 /**
950 * Preprocess the view edit page.
951 */
952 function template_preprocess_views_ui_edit_view(&$vars) {
953 $view = &$vars['view'];
954
955 $vars['save_button'] = drupal_get_form('views_ui_edit_view_form', $view);
956
957 $table = views_fetch_data($view->base_table);
958 $vars['base_table'] = !empty($table['table']['base']['title']) ?
959 $table['table']['base']['title'] : t('Unknown or missing table name');
960
961 views_include('tabs');
962 $tabs = new views_tabset;
963
964 $vars['message'] = '<div class="message">' . t("Click on an item to edit that item's details.") . '</div>';
965
966 if (!$view->set_display('default')) {
967 drupal_set_message(t('This view has a broken default display and cannot be used.'), 'error');
968 }
969
970 foreach ($view->display as $display) {
971 list($title, $body) = views_ui_display_tab($view, $display);
972 // The first display is the default.
973 $tabs->set($display->id, $title, $body);
974 }
975
976 // This is the area that will render beneath the links
977 $form_state = array(
978 'view' => &$view,
979 'ajax' => FALSE,
980 );
981
982 $display_button = drupal_build_form('views_ui_add_display_form', $form_state);
983 $analyze_button = drupal_get_form('views_ui_analyze_view_button', $view);
984 $tabs->add_extra($display_button . $analyze_button);
985
986 $vars['tabs'] = $tabs->render();
987
988 $form_state = array(
989 'display_id' => 'default',
990 'view_args' => '',
991 'rerender' => FALSE,
992 'no_redirect' => TRUE,
993 'view' => &$view,
994 'input' => array(),
995 );
996 $vars['preview'] = drupal_build_form('views_ui_preview_form', $form_state);
997
998 $vars['locked'] = NULL;
999 if (isset($view->locked) && is_object($view->locked)) {
1000 $account = user_load($view->locked->uid);
1001 $vars['locked'] = theme('username', $account);
1002 $vars['lock_age'] = format_interval(time() - $view->locked->updated);
1003 $vars['break'] = url('admin/build/views/break-lock/' . $view->name);
1004 }
1005
1006 $vars['quick_links_raw'] = array(
1007 array(
1008 'title' => t('Export'),
1009 'alt' => t("Export this view"),
1010 'href' => "admin/build/views/export/$view->name",
1011 ),
1012 array(
1013 'title' => t('Clone'),
1014 'alt' => t("Create a copy of this view"),
1015 'href' => "admin/build/views/clone/$view->name",
1016 ),
1017 );
1018
1019 $paths = array();
1020 foreach ($view->display as $id => $display) {
1021 if (!empty($display->handler) && $display->handler->has_path()) {
1022 $path = $display->handler->get_path();
1023 if (strpos($path, '%') === FALSE && !isset($paths[$path])) {
1024 $vars['quick_links_raw'][] = array(
1025 'title' => t('View "@display"', array('@display' => $display->display_title)),
1026 'alt' => t("Go to the real page for this display"),
1027 'href' => $path,
1028 );
1029 // Displays can have the same path; no point in showing more than one link.
1030 $paths[$path] = TRUE;
1031 }
1032 }
1033 }
1034
1035 $vars['quick_links'] = theme('links', $vars['quick_links_raw']);
1036 views_add_css('views-admin');
1037 views_add_css('views');
1038 views_add_js('ajax');
1039 drupal_add_js('misc/jquery.form.js');
1040
1041 // Also add any js files required by plugins:
1042 $plugins = views_fetch_plugin_data();
1043 foreach ($plugins as $type => $type_plugins) {
1044 foreach ($type_plugins as $name => $plugin) {
1045 if (!empty($plugin['js'])) {
1046 foreach ($plugin['js'] as $file) {
1047 drupal_add_js($file);
1048 }
1049 }
1050 }
1051 }
1052
1053 $settings = array('views' => array('ajax' => array(
1054 'id' => '#views-ajax-pad',
1055 'title' => '#views-ajax-title',
1056 'defaultForm' => $vars['message'],
1057 )));
1058
1059 drupal_add_js($settings, 'setting');
1060 }
1061
1062 function template_preprocess_views_ui_edit_tab(&$vars) {
1063 $view = $vars['view'];
1064 $display = $vars['display'];
1065 $plugin = $display->handler->definition;
1066
1067 $top = $left = $middle = $right = '';
1068
1069 // If this form was submitted it was already handled, so force it not to
1070 // submit again.
1071
1072 $vars['remove'] = '';
1073 if (empty($plugin['no remove'])) {
1074 if (!empty($_POST['form_id']) && $_POST['form_id'] == 'views_ui_remove_display_form') {
1075 unset($_POST['form_id']);
1076 }
1077 $form_state = array('view' => &$view, 'display_id' => $display->id, 'ajax' => FALSE);
1078 $vars['remove'] = drupal_build_form('views_ui_remove_display_form', $form_state);
1079 }
1080
1081 // basic fields
1082 $vars['title'] = check_plain($display->display_title);
1083 $vars['description'] = check_plain($plugin['help']);
1084
1085 // Special fields if tihs is the default display.
1086 $vars['default'] = ($display->id == 'default');
1087 $vars['details_class'] = views_ui_item_css('details');
1088 if (!empty($view->changed_sections['details'])) {
1089 $vars['details_changed'] = TRUE;
1090 }
1091
1092 $tag = empty($view->tag) ? t('None') : $view->tag;
1093 $vars['details'] = t('Tag') . ': ' . l($tag, "admin/build/views/nojs/details/$view->name", array('attributes' => array('class' =