Commit 057dd511 authored by webchick's avatar webchick

Issue #1919142 by tim.plunkett, dawehner: Convert Views UI AJAX forms to use FormInterface.

parent e357af4a
......@@ -365,7 +365,7 @@ public function buildOptionsForm(&$form, &$form_state) {
'#ajax' => array(
'path' => views_ui_build_form_url($form_state),
),
'#submit' => array('views_ui_config_item_form_submit_temporary'),
'#submit' => array(array($this, 'submitTemporaryForm')),
'#executes_submit_callback' => TRUE,
);
......
......@@ -94,7 +94,7 @@ class View extends ConfigEntityBase implements ViewStorageInterface {
*
* @var array
*/
protected $display;
protected $display = array();
/**
* The name of the base field to use.
......
......@@ -937,4 +937,86 @@ public static function breakPhraseString($str, &$handler = NULL) {
return $handler;
}
/**
* Displays the Expose form.
*/
public function displayExposedForm($form, &$form_state) {
$item = &$this->options;
// flip
$item['exposed'] = empty($item['exposed']);
// If necessary, set new defaults:
if ($item['exposed']) {
$this->defaultExposeOptions();
}
$form_state['view']->get('executable')->setItem($form_state['display_id'], $form_state['type'], $form_state['id'], $item);
$form_state['view']->addFormToStack($form_state['form_key'], $form_state['display_id'], $form_state['type'], $form_state['id'], TRUE, TRUE);
views_ui_cache_set($form_state['view']);
$form_state['rerender'] = TRUE;
$form_state['rebuild'] = TRUE;
$form_state['force_expose_options'] = TRUE;
}
/**
* A submit handler that is used for storing temporary items when using
* multi-step changes, such as ajax requests.
*/
public function submitTemporaryForm($form, &$form_state) {
// Run it through the handler's submit function.
$this->submitOptionsForm($form['options'], $form_state);
$item = $this->options;
$types = ViewExecutable::viewsHandlerTypes();
// For footer/header $handler_type is area but $type is footer/header.
// For all other handle types it's the same.
$handler_type = $type = $form_state['type'];
if (!empty($types[$type]['type'])) {
$handler_type = $types[$type]['type'];
}
$override = NULL;
$executable = $form_state['view']->get('executable');
if ($executable->display_handler->useGroupBy() && !empty($item['group_type'])) {
if (empty($executable->query)) {
$executable->initQuery();
}
$aggregate = $executable->query->get_aggregation_info();
if (!empty($aggregate[$item['group_type']]['handler'][$type])) {
$override = $aggregate[$item['group_type']]['handler'][$type];
}
}
// Create a new handler and unpack the options from the form onto it. We
// can use that for storage.
$handler = views_get_handler($item['table'], $item['field'], $handler_type, $override);
$handler->init($executable, $executable->display_handler, $item);
// Add the incoming options to existing options because items using
// the extra form may not have everything in the form here.
$options = $form_state['values']['options'] + $this->options;
// This unpacks only options that are in the definition, ensuring random
// extra stuff on the form is not sent through.
$handler->unpackOptions($handler->options, $options, NULL, FALSE);
// Store the item back on the view.
$executable = $form_state['view']->get('executable');
$executable->temporary_options[$type][$form_state['id']] = $handler->options;
// @todo Decide if \Drupal\views_ui\Form\Ajax\ViewsFormBase::getForm() is
// perhaps the better place to fix the issue.
// \Drupal\views_ui\Form\Ajax\ViewsFormBase::getForm() drops the current
// form from the stack, even if it's an #ajax. So add the item back to the top
// of the stack.
$form_state['view']->addFormToStack($form_state['form_key'], $form_state['display_id'], $type, $item['id'], TRUE);
$form_state['rerender'] = TRUE;
$form_state['rebuild'] = TRUE;
// Write to cache
views_ui_cache_set($form_state['view']);
}
}
......@@ -1837,7 +1837,7 @@ public function buildOptionsForm(&$form, &$form_state) {
$form['box']['change'] = array(
'#type' => 'submit',
'#value' => t('Change theme'),
'#submit' => array('views_ui_edit_display_form_change_theme'),
'#submit' => array(array($this, 'changeThemeForm')),
);
$form['analysis'] = array(
......@@ -1851,7 +1851,7 @@ public function buildOptionsForm(&$form, &$form_state) {
$form['rescan_button']['button'] = array(
'#type' => 'submit',
'#value' => t('Rescan template files'),
'#submit' => array('views_ui_config_item_form_rescan'),
'#submit' => array(array($this, 'rescanThemes')),
);
$form['rescan_button']['markup'] = array(
'#markup' => '<div class="description">' . t("<strong>Important!</strong> When adding, removing, or renaming template files, it is necessary to make Drupal aware of the changes by making it rescan the files on your system. By clicking this button you clear Drupal's theme registry and thereby trigger this rescanning process. The highlighted templates above will then reflect the new state of your system.") . '</div>',
......@@ -2020,6 +2020,38 @@ public function buildOptionsForm(&$form, &$form_state) {
}
}
/**
* Submit hook to clear Drupal's theme registry (thereby triggering
* a templates rescan).
*/
public function rescanThemes($form, &$form_state) {
drupal_theme_rebuild();
// The 'Theme: Information' page is about to be shown again. That page
// analyzes the output of theme_get_registry(). However, this latter
// function uses an internal cache (which was initialized before we
// called drupal_theme_rebuild()) so it won't reflect the
// current state of our theme registry. The only way to clear that cache
// is to re-initialize the theme system:
unset($GLOBALS['theme']);
drupal_theme_initialize();
$form_state['rerender'] = TRUE;
$form_state['rebuild'] = TRUE;
}
/**
* Displays the Change Theme form.
*/
public function changeThemeForm($form, &$form_state) {
// This is just a temporary variable.
$form_state['view']->theme = $form_state['values']['theme'];
views_ui_cache_set($form_state['view']);
$form_state['rerender'] = TRUE;
$form_state['rebuild'] = TRUE;
}
/**
* Format a list of theme templates for output by the theme info helper.
*/
......@@ -2129,7 +2161,7 @@ public function submitOptionsForm(&$form, &$form_state) {
$access = array('type' => $form_state['values']['access']['type']);
$this->setOption('access', $access);
if ($plugin->usesOptions()) {
$form_state['view']->addFormToStack('display', $this->display['id'], array('access_options'));
$form_state['view']->addFormToStack('display', $this->display['id'], 'access_options');
}
}
}
......@@ -2152,7 +2184,7 @@ public function submitOptionsForm(&$form, &$form_state) {
$cache = array('type' => $form_state['values']['cache']['type']);
$this->setOption('cache', $cache);
if ($plugin->usesOptions()) {
$form_state['view']->addFormToStack('display', $this->display['id'], array('cache_options'));
$form_state['view']->addFormToStack('display', $this->display['id'], 'cache_options');
}
}
}
......@@ -2213,7 +2245,7 @@ public function submitOptionsForm(&$form, &$form_state) {
// send ajax form to options page if we use it.
if ($plugin->usesOptions()) {
$form_state['view']->addFormToStack('display', $this->display['id'], array('row_options'));
$form_state['view']->addFormToStack('display', $this->display['id'], 'row_options');
}
}
}
......@@ -2229,7 +2261,7 @@ public function submitOptionsForm(&$form, &$form_state) {
$this->setOption($section, $row);
// send ajax form to options page if we use it.
if ($plugin->usesOptions()) {
$form_state['view']->addFormToStack('display', $this->display['id'], array('style_options'));
$form_state['view']->addFormToStack('display', $this->display['id'], 'style_options');
}
}
}
......@@ -2263,7 +2295,7 @@ public function submitOptionsForm(&$form, &$form_state) {
$exposed_form = array('type' => $form_state['values']['exposed_form']['type'], 'options' => array());
$this->setOption('exposed_form', $exposed_form);
if ($plugin->usesOptions()) {
$form_state['view']->addFormToStack('display', $this->display['id'], array('exposed_form_options'));
$form_state['view']->addFormToStack('display', $this->display['id'], 'exposed_form_options');
}
}
}
......@@ -2290,7 +2322,7 @@ public function submitOptionsForm(&$form, &$form_state) {
$pager = array('type' => $form_state['values']['pager']['type'], 'options' => $plugin->options);
$this->setOption('pager', $pager);
if ($plugin->usesOptions()) {
$form_state['view']->addFormToStack('display', $this->display['id'], array('pager_options'));
$form_state['view']->addFormToStack('display', $this->display['id'], 'pager_options');
}
}
}
......
......@@ -399,7 +399,7 @@ public function submitOptionsForm(&$form, &$form_state) {
$this->setOption('menu', $form_state['values']['menu']);
// send ajax form to options page if we use it.
if ($form_state['values']['menu']['type'] == 'default tab') {
$form_state['view']->addFormToStack('display', $this->display['id'], array('tab_options'));
$form_state['view']->addFormToStack('display', $this->display['id'], 'tab_options');
}
break;
case 'tab_options':
......
......@@ -398,7 +398,7 @@ function show_build_group_button(&$form, &$form_state) {
'#limit_validation_errors' => array(),
'#type' => 'submit',
'#value' => t('Grouped filters'),
'#submit' => array('views_ui_config_item_form_build_group'),
'#submit' => array(array($this, 'buildGroupForm')),
);
$form['group_button']['radios']['radios']['#default_value'] = 0;
}
......@@ -407,11 +407,35 @@ function show_build_group_button(&$form, &$form_state) {
'#limit_validation_errors' => array(),
'#type' => 'submit',
'#value' => t('Single filter'),
'#submit' => array('views_ui_config_item_form_build_group'),
'#submit' => array(array($this, 'buildGroupForm')),
);
$form['group_button']['radios']['radios']['#default_value'] = 1;
}
}
/**
* Displays the Build Group form.
*/
public function buildGroupForm($form, &$form_state) {
$item = &$this->options;
// flip. If the filter was a group, set back to a standard filter.
$item['is_grouped'] = empty($item['is_grouped']);
// If necessary, set new defaults:
if ($item['is_grouped']) {
$this->build_group_options();
}
$form_state['view']->get('executable')->setItem($form_state['display_id'], $form_state['type'], $form_state['id'], $item);
$form_state['view']->addFormToStack($form_state['form_key'], $form_state['display_id'], $form_state['type'], $form_state['id'], TRUE, TRUE);
views_ui_cache_set($form_state['view']);
$form_state['rerender'] = TRUE;
$form_state['rebuild'] = TRUE;
$form_state['force_build_group_options'] = TRUE;
}
/**
* Shortcut to display the expose/hide button.
*/
......@@ -443,7 +467,7 @@ public function showExposeButton(&$form, &$form_state) {
'#limit_validation_errors' => array(),
'#type' => 'submit',
'#value' => t('Expose filter'),
'#submit' => array('views_ui_config_item_form_expose'),
'#submit' => array(array($this, 'displayExposedForm')),
);
$form['expose_button']['checkbox']['checkbox']['#default_value'] = 0;
}
......@@ -455,7 +479,7 @@ public function showExposeButton(&$form, &$form_state) {
'#limit_validation_errors' => array(),
'#type' => 'submit',
'#value' => t('Hide filter'),
'#submit' => array('views_ui_config_item_form_expose'),
'#submit' => array(array($this, 'displayExposedForm')),
);
$form['expose_button']['checkbox']['checkbox']['#default_value'] = 1;
}
......@@ -1038,7 +1062,7 @@ function build_group_form(&$form, &$form_state) {
'#suffix' => '</div>',
'#type' => 'submit',
'#value' => t('Add another item'),
'#submit' => array('views_ui_config_item_form_add_group'),
'#submit' => array(array($this, 'addGroupForm')),
);
$js = array();
......@@ -1058,6 +1082,23 @@ function build_group_form(&$form, &$form_state) {
}
}
/**
* Add a new group to the exposed filter groups.
*/
public function addGroupForm($form, &$form_state) {
$item = &$this->options;
// Add a new row.
$item['group_info']['group_items'][] = array();
$form_state['view']->get('executable')->setItem($form_state['display_id'], $form_state['type'], $form_state['id'], $item);
views_ui_cache_set($form_state['view']);
$form_state['rerender'] = TRUE;
$form_state['rebuild'] = TRUE;
$form_state['force_build_group_options'] = TRUE;
}
/**
* Make some translations to a form item to make it more suitable to
......
......@@ -117,7 +117,7 @@ public function showExposeButton(&$form, &$form_state) {
'#limit_validation_errors' => array(),
'#type' => 'submit',
'#value' => t('Expose sort'),
'#submit' => array('views_ui_config_item_form_expose'),
'#submit' => array(array($this, 'displayExposedForm')),
);
$form['expose_button']['checkbox']['checkbox']['#default_value'] = 0;
}
......@@ -129,7 +129,7 @@ public function showExposeButton(&$form, &$form_state) {
'#limit_validation_errors' => array(),
'#type' => 'submit',
'#value' => t('Hide sort'),
'#submit' => array('views_ui_config_item_form_expose'),
'#submit' => array(array($this, 'displayExposedForm')),
);
$form['expose_button']['checkbox']['checkbox']['#default_value'] = 1;
}
......
......@@ -103,7 +103,9 @@ public function testStorePagerSettings() {
'pager_options[items_per_page]' => 10,
);
$this->drupalPost('admin/structure/views/nojs/display/test_store_pager_settings/default/pager_options', $edit, t('Apply'));
$this->assertText('20 items');
$this->assertText('10 items', 'The default value has been changed.');
$this->drupalGet('admin/structure/views/view/test_store_pager_settings/edit/page_1');
$this->assertText('20 items', 'The original value remains unchanged.');
}
......
......@@ -99,7 +99,7 @@ public function testUICRUD() {
$this->assertUrl($edit_handler_url, array(), 'The user got redirected to the handler edit form.');
$this->drupalPost(NULL, array(), t('Apply'));
$this->assertUrl('admin/structure/views/view/test_view_empty/edit', array(), 'The user got redirected to the views edit form.');
$this->assertUrl('admin/structure/views/view/test_view_empty/edit/default', array(), 'The user got redirected to the views edit form.');
$this->assertLinkByHref($edit_handler_url, 0, 'The handler edit link appears in the UI.');
......
......@@ -81,23 +81,26 @@ public function create(array $values) {
* The view entity to attach default displays options.
*/
protected function mergeDefaultDisplaysOptions(EntityInterface $entity) {
if (isset($entity->display) && is_array($entity->display)) {
$displays = array();
foreach ($entity->get('display') as $key => $options) {
$options += array(
'display_options' => array(),
'display_plugin' => NULL,
'id' => NULL,
'display_title' => '',
'position' => NULL,
);
// Add the defaults for the display.
$displays[$key] = $options;
}
$entity->set('display', $displays);
$displays = array();
foreach ($entity->get('display') as $key => $options) {
$options += array(
'display_options' => array(),
'display_plugin' => NULL,
'id' => NULL,
'display_title' => '',
'position' => NULL,
);
// Add the defaults for the display.
$displays[$key] = $options;
}
// Sort the displays.
uasort($displays, function ($display1, $display2) {
if ($display1['position'] != $display2['position']) {
return $display1['position'] < $display2['position'] ? -1 : 1;
}
return 0;
});
$entity->set('display', $displays);
}
}
This diff is collapsed.
<?php
/**
* @file
* Contains \Drupal\views_ui\Form\Ajax\AddItem.
*/
namespace Drupal\views_ui\Form\Ajax;
use Drupal\views\ViewExecutable;
use Drupal\views\ViewStorageInterface;
/**
* Provides a form for adding an item in the Views UI.
*/
class AddItem extends ViewsFormBase {
/**
* Constucts a new AddItem object.
*/
public function __construct($type = NULL) {
$this->setType($type);
}
/**
* Implements \Drupal\views_ui\Form\Ajax\ViewsFormInterface::getFormKey().
*/
public function getFormKey() {
return 'add-item';
}
/**
* Overrides \Drupal\views_ui\Form\Ajax\ViewsFormBase::getForm().
*/
public function getForm(ViewStorageInterface $view, $display_id, $js, $type = NULL) {
$this->setType($type);
return parent::getForm($view, $display_id, $js);
}
/**
* Implements \Drupal\Core\Form\FormInterface::getFormID().
*/
public function getFormID() {
return 'views_ui_add_item_form';
}
/**
* Implements \Drupal\Core\Form\FormInterface::buildForm().
*/
public function buildForm(array $form, array &$form_state) {
$view = &$form_state['view'];
$display_id = $form_state['display_id'];
$type = $form_state['type'];
$form = array(
'options' => array(
'#theme_wrappers' => array('container'),
'#attributes' => array('class' => array('scroll')),
),
);
$executable = $view->get('executable');
if (!$executable->setDisplay($display_id)) {
views_ajax_error(t('Invalid display id @display', array('@display' => $display_id)));
}
$display = &$executable->displayHandlers->get($display_id);
$types = ViewExecutable::viewsHandlerTypes();
$ltitle = $types[$type]['ltitle'];
$section = $types[$type]['plural'];
if (!empty($types[$type]['type'])) {
$type = $types[$type]['type'];
}
$form['#title'] = t('Add @type', array('@type' => $ltitle));
$form['#section'] = $display_id . 'add-item';
// Add the display override dropdown.
views_ui_standard_display_dropdown($form, $form_state, $section);
// Figure out all the base tables allowed based upon what the relationships provide.
$base_tables = $executable->getBaseTables();
$options = views_fetch_fields(array_keys($base_tables), $type, $display->useGroupBy(), $form_state['type']);
if (!empty($options)) {
$form['override']['controls'] = array(
'#theme_wrappers' => array('container'),
'#id' => 'views-filterable-options-controls',
'#attributes' => array('class' => array('container-inline')),
);
$form['override']['controls']['options_search'] = array(
'#type' => 'textfield',
'#title' => t('Search'),
);
$groups = array('all' => t('- All -'));
$form['override']['controls']['group'] = array(
'#type' => 'select',
'#title' => t('Type'),
'#options' => array(),
);
$form['options']['name'] = array(
'#prefix' => '<div class="views-radio-box form-checkboxes views-filterable-options">',
'#suffix' => '</div>',
'#tree' => TRUE,
'#default_value' => 'all',
);
// Group options first to simplify the usage of #states.
$grouped_options = array();
foreach ($options as $key => $option) {
$group = preg_replace('/[^a-z0-9]/', '-', strtolower($option['group']));
$groups[$group] = $option['group'];
$grouped_options[$group][$key] = $option;
if (!empty($option['aliases']) && is_array($option['aliases'])) {
foreach ($option['aliases'] as $id => $alias) {
if (empty($alias['base']) || !empty($base_tables[$alias['base']])) {
$copy = $option;
$copy['group'] = $alias['group'];
$copy['title'] = $alias['title'];
if (isset($alias['help'])) {
$copy['help'] = $alias['help'];
}
$group = preg_replace('/[^a-z0-9]/', '-', strtolower($copy['group']));
$groups[$group] = $copy['group'];
$grouped_options[$group][$key . '$' . $id] = $copy;
}
}
}
}
foreach ($grouped_options as $group => $group_options) {
$zebra = 0;
foreach ($group_options as $key => $option) {
$zebra_class = ($zebra % 2) ? 'odd' : 'even';
$form['options']['name'][$key] = array(
'#type' => 'checkbox',
'#title' => t('!group: !field', array('!group' => $option['group'], '!field' => $option['title'])),
'#description' => $option['help'],
'#return_value' => $key,
'#prefix' => "<div class='$zebra_class filterable-option'>",
'#suffix' => '</div>',
'#states' => array(
'visible' => array(
array(
':input[name="override[controls][group]"]' => array('value' => 'all'),
),
array(
':input[name="override[controls][group]"]' => array('value' => $group),
),
)
)
);
$zebra++;
}
}
$form['override']['controls']['group']['#options'] = $groups;
}
else {
$form['options']['markup'] = array(
'#markup' => '<div class="form-item">' . t('There are no @types available to add.', array('@types' => $ltitle)) . '</div>',
);
}
// Add a div to show the selected items
$form['selected'] = array(
'#type' => 'item',
'#markup' => '<div class="views-selected-options"></div>',
'#title' => t('Selected') . ':',
'#theme_wrappers' => array('form_element', 'views_ui_container'),
'#attributes' => array('class' => array('container-inline', 'views-add-form-selected')),
);
$view->getStandardButtons($form, $form_state, 'views_ui_add_item_form', t('Add and configure @types', array('@types' => $ltitle)));
// Remove the default submit function.
$form['buttons']['submit']['#submit'] = array_filter($form['buttons']['submit']['#submit'], function($var) {
return !(is_array($var) && isset($var[1]) && $var[1] == 'standardSubmit');
});
$form['buttons']['submit']['#submit'][] = array($view, 'submitItemAdd');
return $form;
}
}
<?php
/**
* @file
* Contains \Drupal\views_ui\Form\Ajax\Analyze.
*/
namespace Drupal\views_ui\Form\Ajax;
use Drupal\views_ui\ViewUI;
use Drupal\views\Analyzer;
/**
* Displays analysis information for a view.
*/
class Analyze extends ViewsFormBase {
/**
* Implements \Drupal\views_ui\Form\Ajax\ViewsFormInterface::getFormKey().
*/
public function getFormKey() {
return 'analyze';
}
/**
* Implements \Drupal\Core\Form\FormInterface::getFormID().
*/
public function getFormID() {
return 'views_ui_analyze_view_form';
}
/**
* Implements \Drupal\Core\Form\FormInterface::buildForm().
*/
public function buildForm(array $form, array &$form_state) {