summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--css/views-admin.theme-rtl.css4
-rw-r--r--css/views-admin.theme.css8
-rw-r--r--includes/admin.inc337
-rw-r--r--plugins/views_wizard/views_ui_base_views_wizard.class.php70
-rw-r--r--plugins/views_wizard/views_ui_comment_views_wizard.class.php23
-rw-r--r--plugins/views_wizard/views_ui_node_views_wizard.class.php11
-rw-r--r--tests/views_ui.test12
7 files changed, 350 insertions, 115 deletions
diff --git a/css/views-admin.theme-rtl.css b/css/views-admin.theme-rtl.css
index ba99980..1b0c011 100644
--- a/css/views-admin.theme-rtl.css
+++ b/css/views-admin.theme-rtl.css
@@ -152,6 +152,10 @@ div.form-item-displays-live-preview {
padding-right: 25px;
}
+.views-ui-display-tab-bucket.overridden .views-display-setting {
+ margin-right: 15px;
+}
+
/* @end */
/* @group Attachment bucket rows
diff --git a/css/views-admin.theme.css b/css/views-admin.theme.css
index cf93e2d..54133c1 100644
--- a/css/views-admin.theme.css
+++ b/css/views-admin.theme.css
@@ -289,10 +289,6 @@ th.views-ui-operations {
font-weight: bold;
}
-#edit-view-displays-wrapper {
- margin-top: 27px;
-}
-
/* This could be made more general if more than one instance occurs */
#edit-page-style .fieldset-wrapper {
padding-left: 0;
@@ -603,6 +599,10 @@ td.group-title {
zoom: 1;
}
+.views-ui-display-tab-bucket.overridden .views-display-setting {
+ margin-left: 15px; /* LTR */
+}
+
/* @end */
/* @group Attachment bucket drop button */
diff --git a/includes/admin.inc b/includes/admin.inc
index 3abef30..a08a3e0 100644
--- a/includes/admin.inc
+++ b/includes/admin.inc
@@ -324,19 +324,23 @@ function views_ui_add_form($form, &$form_state) {
),
);
- // Everything that can be updated by AJAX goes in here. It is triggered by
- // the "Show" dropdown below.
- $form['displays'] = array(
- '#prefix' => '<div id="edit-view-displays-wrapper">',
- '#suffix' => '</div>',
- );
-
+ // Create a wrapper for the entire dynamic portion of the form. Everything
+ // that can be updated by AJAX goes somewhere inside here. For example, this
+ // is needed by "Show" dropdown (below); it changes the base table of the
+ // view and therefore potentially requires all options on the form to be
+ // dynamically updated.
+ $form['displays'] = array();
+
+ // Create the part of the form that allows the user to select the basic
+ // properties of what the view will display.
$form['displays']['show'] = array(
'#type' => 'fieldset',
'#tree' => TRUE,
'#attributes' => array('class' => array('container-inline')),
);
+ // Create the "Show" dropdown, which allows the base table of the view to be
+ // selected.
$wizard_plugins = views_ui_get_wizards();
$options = array();
foreach ($wizard_plugins as $key => $w) {
@@ -346,28 +350,15 @@ function views_ui_add_form($form, &$form_state) {
'#type' => 'select',
'#title' => t('Show'),
'#options' => $options,
- '#default_value' => 'node',
- '#ajax' => array(
- 'callback' => 'views_ui_add_form_update',
- 'wrapper' => 'edit-view-displays-wrapper',
- ),
);
-
- // Since the "Show" dropdown can't trigger a form submission when
- // JavaScript is disabled, add a submit button to do that.
- $form['displays']['show']['update_wizard_key'] = array(
- '#type' => 'submit',
- '#value' => t('Update options'),
- // Do not trigger form validation errors elsewhere on the page.
- '#limit_validation_errors' => array(
- array('show', 'wizard_key'),
- ),
- // Hide this button when JavaScript is enabled.
- '#attributes' => array('class' => array('js-hide')),
- '#submit' => array('views_ui_show_nojs_submit'),
- );
-
- $wizard_key = isset($form_state['values']['show']['wizard_key']) ? $form_state['values']['show']['wizard_key'] : $form['displays']['show']['wizard_key']['#default_value'];
+ $show_form = &$form['displays']['show'];
+ $show_form['wizard_key']['#default_value'] = views_ui_get_selected($form_state, array('show', 'wizard_key'), 'node', $show_form['wizard_key']);
+ // Changing this dropdown updates the entire content of $form['displays'] via
+ // AJAX.
+ views_ui_add_ajax_trigger($show_form, 'wizard_key', array('displays'));
+
+ // Build the rest of the form based on the currently selected wizard plugin.
+ $wizard_key = $show_form['wizard_key']['#default_value'];
$get_instance = $wizard_plugins[$wizard_key]['get_instance'];
$wizard_instance = $get_instance($wizard_plugins[$wizard_key]);
$form = $wizard_instance->build_form($form, $form_state);
@@ -395,61 +386,278 @@ function views_ui_add_form($form, &$form_state) {
}
/**
- * Update the add view form.
+ * Gets the current value of a #select element, from within a form constructor function.
+ *
+ * This function is intended for use in highly dynamic forms (in particular the
+ * add view wizard) which are rebuilt in different ways depending on which
+ * triggering element (AJAX or otherwise) was most recently fired. For example,
+ * sometimes it is necessary to decide how to build one dynamic form element
+ * based on the value of a different dynamic form element that may not have
+ * even been present on the form the last time it was submitted. This function
+ * takes care of resolving those conflicts and gives you the proper current
+ * value of the requested #select element.
+ *
+ * By necessity, this function sometimes uses non-validated user input from
+ * $form_state['input'] in making its determination. Although it performs some
+ * minor validation of its own, it is not complete. The intention is that the
+ * return value of this function should only be used to help decide how to
+ * build the current form the next time it is reloaded, not to be saved as if
+ * it had gone through the normal, final form validation process. Do NOT use
+ * the results of this function for any other purpose besides deciding how to
+ * build the next version of the form.
+ *
+ * @param $form_state
+ * The standard associative array containing the current state of the form.
+ * @param $parents
+ * An array of parent keys that point to the part of the submitted form
+ * values that are expected to contain the element's value (in the case where
+ * this form element was actually submitted). In a simple case (assuming
+ * #tree is TRUE throughout the form), if the select element is located in
+ * $form['wrapper']['select'], so that the submitted form values would
+ * normally be found in $form_state['values']['wrapper']['select'], you would
+ * pass array('wrapper', 'select') for this parameter.
+ * @param $default_value
+ * The default value to return if the #select element does not currently have
+ * a proper value set based on the submitted input.
+ * @param $element
+ * An array representing the current version of the #select element within
+ * the form.
+ *
+ * @return
+ * The current value of the #select element. A common use for this is to feed
+ * it back into $element['#default_value'] so that the form will be rendered
+ * with the correct value selected.
*/
-function views_ui_show_nojs_submit($form, &$form_state) {
- $form_state['rebuild'] = TRUE;
+function views_ui_get_selected($form_state, $parents, $default_value, $element) {
+ // For now, don't trust this to work on anything but a #select element.
+ if (!isset($element['#type']) || $element['#type'] != 'select' || !isset($element['#options'])) {
+ return $default_value;
+ }
+
+ // If there is a user-submitted value for this element that matches one of
+ // the currently available options attached to it, use that. We need to check
+ // $form_state['input'] rather than $form_state['values'] here because the
+ // triggering element often has the #limit_validation_errors property set to
+ // prevent unwanted errors elsewhere on the form. This means that the
+ // $form_state['values'] array won't be complete. We could make it complete
+ // by adding each required part of the form to the #limit_validation_errors
+ // property individually as the form is being built, but this is difficult to
+ // do for a highly dynamic and extensible form. This method is much simpler.
+ if (!empty($form_state['input'])) {
+ $key_exists = NULL;
+ $submitted = drupal_array_get_nested_value($form_state['input'], $parents, $key_exists);
+ // Check that the user-submitted value is one of the allowed options before
+ // returning it. This is not a substitute for actual form validation;
+ // rather it is necessary because, for example, the same select element
+ // might have #options A, B, and C under one set of conditions but #options
+ // D, E, F under a different set of conditions. So the form submission
+ // might have occurred with option A selected, but when the form is rebuilt
+ // option A is no longer one of the choices. In that case, we don't want to
+ // use the value that was submitted anymore but rather fall back to the
+ // default value.
+ if ($key_exists && in_array($submitted, array_keys($element['#options']))) {
+ return $submitted;
+ }
+ }
+
+ // Fall back on returning the default value if nothing was returned above.
+ return $default_value;
}
/**
- * Update the add view form via AJAX.
+ * Converts a form element in the add view wizard to be AJAX-enabled.
*
- * @return
- * The part of the form that has changed.
+ * This function takes a form element and adds AJAX behaviors to it such that
+ * changing it triggers another part of the form to update automatically. It
+ * also adds a submit button to the form that appears next to the triggering
+ * element and that duplicates its functionality for users who do not have
+ * JavaScript enabled (the button is automatically hidden for users who do have
+ * JavaScript).
+ *
+ * To use this function, call it directly from your form builder function
+ * immediately after you have defined the form element that will serve as the
+ * JavaScript trigger. Calling it elsewhere (such as in hook_form_alter()) may
+ * mean that the non-JavaScript fallback button does not appear in the correct
+ * place in the form.
+ *
+ * @param $wrapping_element
+ * The element whose child will server as the AJAX trigger. For example, if
+ * $form['some_wrapper']['triggering_element'] represents the element which
+ * will trigger the AJAX behavior, you would pass $form['some_wrapper'] for
+ * this parameter.
+ * @param $trigger_key
+ * The key within the wrapping element that identifies which of its children
+ * serves as the AJAX trigger. In the above example, you would pass
+ * 'triggering_element' for this parameter.
+ * @param $refresh_parents
+ * An array of parent keys that point to the part of the form that will be
+ * refreshed by AJAX. For example, if triggering the AJAX behavior should
+ * cause $form['dynamic_content']['section'] to be refreshed, you would pass
+ * array('dynamic_content', 'section') for this parameter.
*/
-function views_ui_add_form_update($form, $form_state) {
- return $form['displays'];
+function views_ui_add_ajax_trigger(&$wrapping_element, $trigger_key, $refresh_parents) {
+ $seen_ids = &drupal_static(__FUNCTION__, array());
+ $seen_buttons = &drupal_static(__FUNCTION__, array());
+
+ // Add the AJAX behavior to the triggering element.
+ $triggering_element = &$wrapping_element[$trigger_key];
+ $triggering_element['#ajax']['callback'] = 'views_ui_ajax_update_form';
+ // We do not use drupal_html_id() to get an ID for the AJAX wrapper, because
+ // it remembers IDs across AJAX requests (and won't reuse them), but in our
+ // case we need to use the same ID from request to request so that the
+ // wrapper can be recognized by the AJAX system and its content can be
+ // dynamically updated. So instead, we will keep track of duplicate IDs
+ // (within a single request) on our own, later in this function.
+ $triggering_element['#ajax']['wrapper'] = 'edit-view-' . implode('-', $refresh_parents) . '-wrapper';
+
+ // Add a submit button for users who do not have JavaScript enabled. It
+ // should be displayed next to the triggering element on the form.
+ $button_key = $trigger_key . '_trigger_update';
+ $wrapping_element[$button_key] = array(
+ '#type' => 'submit',
+ // Hide this button when JavaScript is enabled.
+ '#attributes' => array('class' => array('js-hide')),
+ '#submit' => array('views_ui_nojs_submit'),
+ // Add a process function to limit this button's validation errors to the
+ // triggering element only. We have to do this in #process since until the
+ // form API has added the #parents property to the triggering element for
+ // us, we don't have any (easy) way to find out where its submitted values
+ // will eventually appear in $form_state['values'].
+ '#process' => array_merge(array('views_ui_add_limited_validation'), element_info_property('submit', '#process', array())),
+ // Add an after-build function that inserts a wrapper around the region of
+ // the form that needs to be refreshed by AJAX (so that the AJAX system can
+ // detect and dynamically update it). This is done in #after_build because
+ // it's a convenient place where we have automatic access to the complete
+ // form array, but also to minimize the chance that the HTML we add will
+ // get clobbered by code that runs after we have added it.
+ '#after_build' => array_merge(element_info_property('submit', '#after_build', array()), array('views_ui_add_ajax_wrapper')),
+ );
+ // Copy #weight and #access from the triggering element to the button, so
+ // that the two elements will be displayed together.
+ foreach (array('#weight', '#access') as $property) {
+ if (isset($triggering_element[$property])) {
+ $wrapping_element[$button_key][$property] = $triggering_element[$property];
+ }
+ }
+ // For easiest integration with the form API and the testing framework, we
+ // always give the button a unique #value, rather than playing around with
+ // #name.
+ $button_title = !empty($triggering_element['#title']) ? $triggering_element['#title'] : $trigger_key;
+ if (empty($seen_buttons[$button_title])) {
+ $wrapping_element[$button_key]['#value'] = t('Update "@title" choice', array(
+ '@title' => $button_title,
+ ));
+ $seen_buttons[$button_title] = 1;
+ }
+ else {
+ $wrapping_element[$button_key]['#value'] = t('Update "@title" choice (@number)', array(
+ '@title' => $button_title,
+ '@number' => ++$seen_buttons[$button_title],
+ ));
+ }
+
+ // Attach custom data to the triggering element and submit button, so we can
+ // use it in both the process function and AJAX callback.
+ $ajax_data = array(
+ 'wrapper' => $triggering_element['#ajax']['wrapper'],
+ 'trigger_key' => $trigger_key,
+ 'refresh_parents' => $refresh_parents,
+ // Keep track of duplicate wrappers so we don't add the same wrapper to the
+ // page more than once.
+ 'duplicate_wrapper' => !empty($seen_ids[$triggering_element['#ajax']['wrapper']]),
+ );
+ $seen_ids[$triggering_element['#ajax']['wrapper']] = TRUE;
+ $triggering_element['#views_ui_ajax_data'] = $ajax_data;
+ $wrapping_element[$button_key]['#views_ui_ajax_data'] = $ajax_data;
}
/**
- * Update the add view style form via AJAX.
- *
- * @return
- * The part of the form that has changed.
+ * Processes a non-JavaScript fallback submit button to limit its validation errors.
*/
-function views_ui_add_form_update_style_page($form, $form_state) {
- return $form['displays']['page']['options'];
+function views_ui_add_limited_validation($element, &$form_state) {
+ // Retrieve the AJAX triggering element so we can determine its parents. (We
+ // know it's at the same level of the complete form array as the submit
+ // button, so all we have to do to find it is swap out the submit button's
+ // last array parent.)
+ $array_parents = $element['#array_parents'];
+ array_pop($array_parents);
+ $array_parents[] = $element['#views_ui_ajax_data']['trigger_key'];
+ $ajax_triggering_element = drupal_array_get_nested_value($form_state['complete form'], $array_parents);
+
+ // Limit this button's validation to the AJAX triggering element, so it can
+ // update the form for that change without requiring that the rest of the
+ // form be filled out properly yet.
+ $element['#limit_validation_errors'] = array($ajax_triggering_element['#parents']);
+
+ // If we are in the process of a form submission and this is the button that
+ // was clicked, the form API workflow in form_builder() will have already
+ // copied it to $form_state['triggering_element'] before our #process
+ // function is run. So we need to make the same modifications in $form_state
+ // as we did to the element itself, to ensure that #limit_validation_errors
+ // will actually be set in the correct place.
+ if (!empty($form_state['triggering_element'])) {
+ $clicked_button = &$form_state['triggering_element'];
+ if ($clicked_button['#name'] == $element['#name'] && $clicked_button['#value'] == $element['#value']) {
+ $clicked_button['#limit_validation_errors'] = $element['#limit_validation_errors'];
+ }
+ }
+
+ return $element;
}
/**
- * Update the add view style form via AJAX.
+ * After-build function that adds a wrapper to a form region (for AJAX refreshes).
*
- * @return
- * The part of the form that has changed.
+ * This function inserts a wrapper around the region of the form that needs to
+ * be refreshed by AJAX, based on information stored in the corresponding
+ * submit button form element.
*/
-function views_ui_add_form_update_style_block($form, $form_state) {
- return $form['displays']['page']['options'];
-}
+function views_ui_add_ajax_wrapper($element, &$form_state) {
+ // Don't add the wrapper <div> if the same one was already inserted on this
+ // form.
+ if (empty($element['#views_ui_ajax_data']['duplicate_wrapper'])) {
+ // Find the region of the complete form that needs to be refreshed by AJAX.
+ // This was earlier stored in a property on the element.
+ $complete_form = &$form_state['complete form'];
+ $refresh_parents = $element['#views_ui_ajax_data']['refresh_parents'];
+ $refresh_element = drupal_array_get_nested_value($complete_form, $refresh_parents);
+
+ // The HTML ID that AJAX expects was also stored in a property on the
+ // element, so use that information to insert the wrapper <div> here.
+ $id = $element['#views_ui_ajax_data']['wrapper'];
+ $refresh_element += array(
+ '#prefix' => '',
+ '#suffix' => '',
+ );
+ $refresh_element['#prefix'] = '<div id="' . $id . '">' . $refresh_element['#prefix'];
+ $refresh_element['#suffix'] .= '</div>';
+
+ // Copy the element that needs to be refreshed back into the form, with our
+ // modifications to it.
+ drupal_array_set_nested_value($complete_form, $refresh_parents, $refresh_element);
+ }
+ return $element;
+}
/**
- * Update the add view style row_options via AJAX.
+ * Updates a part of the add view form via AJAX.
*
* @return
* The part of the form that has changed.
*/
-function views_ui_add_form_update_row_page($form, $form_state) {
- return $form['displays']['page']['options']['style']['row_options'];
+function views_ui_ajax_update_form($form, $form_state) {
+ // The region that needs to be updated was stored in a property of the
+ // triggering element by views_ui_add_ajax_trigger(), so all we have to do is
+ // retrieve that here.
+ return drupal_array_get_nested_value($form, $form_state['triggering_element']['#views_ui_ajax_data']['refresh_parents']);
}
/**
- * Update the add view row_options form via AJAX.
- *
- * @return
- * The part of the form that has changed.
+ * Non-Javascript fallback for updating the add view form.
*/
-function views_ui_add_form_update_row_block($form, $form_state) {
- return $form['displays']['block']['options']['style']['row_options'];
+function views_ui_nojs_submit($form, &$form_state) {
+ $form_state['rebuild'] = TRUE;
}
/**
@@ -985,6 +1193,13 @@ function views_ui_edit_form($form, &$form_state, $view, $display_id = NULL) {
'#id' => 'views-ajax-body',
'#markup' => views_ui_get_default_ajax_message(),
);
+
+ // WYSIWYG does not yet work on AJAX returned content unless the editor
+ // libraries are loaded on the base page (http://drupal.org/node/356480).
+ // @todo Remove this when that issue is resolved.
+ if (module_exists('wysiwyg')) {
+ $form['dummy_text_format'] = array('#type' => 'text_format', '#prefix' => '<div style="display:none">', '#suffix' => '</div>');
+ }
}
return $form;
@@ -2409,11 +2624,19 @@ function views_ui_ajax_form($js, $key, $view, $display_id) {
unset($view->form_cache);
}
+ // With the below logic, we may end up rendering a form twice (or two forms
+ // each sharing the same element ids), potentially resulting in
+ // drupal_add_js() being called twice to add the same setting. drupal_get_js()
+ // is ok with that, but until ajax_render() is (http://drupal.org/node/208611),
+ // reset the drupal_add_js() static before rendering the second time.
+ $drupal_add_js_original = drupal_add_js();
+ $drupal_add_js = &drupal_static('drupal_add_js');
$output = views_ajax_form_wrapper($form_state['form_id'], $form_state);
if ($form_state['submitted'] && empty($form_state['rerender'])) {
// Sometimes we need to re-generate the form for multi-step type operations.
$object = NULL;
if (!empty($view->stack)) {
+ $drupal_add_js = $drupal_add_js_original;
$stack = $view->stack;
$top = array_shift($stack);
$top[0] = $js;
diff --git a/plugins/views_wizard/views_ui_base_views_wizard.class.php b/plugins/views_wizard/views_ui_base_views_wizard.class.php
index 64fe394..0e23f78 100644
--- a/plugins/views_wizard/views_ui_base_views_wizard.class.php
+++ b/plugins/views_wizard/views_ui_base_views_wizard.class.php
@@ -113,23 +113,27 @@ class ViewsUiBaseViewsWizard implements ViewsWizardInterface {
'#type' => 'fieldset',
'#attributes' => array('class' => array('container-inline')),
);
+
+ // Create the dropdown for choosing the display format.
$form['displays']['page']['options']['style']['style_plugin'] = array(
'#title' => t('Display format'),
'#help_topic' => 'style',
'#type' => 'select',
'#options' => $style_options,
- '#default_value' => 'default',
- '#ajax' => array(
- 'callback' => 'views_ui_add_form_update_style_page',
- 'wrapper' => 'edit-page-style-plugin',
- ),
);
+ $style_form = &$form['displays']['page']['options']['style'];
+ $style_form['style_plugin']['#default_value'] = views_ui_get_selected($form_state, array('page', 'style', 'style_plugin'), 'default', $style_form['style_plugin']);
+ // Changing this dropdown updates $form['displays']['page']['options'] via
+ // AJAX.
+ views_ui_add_ajax_trigger($style_form, 'style_plugin', array('displays', 'page', 'options'));
+
$this->build_form_style($form, $form_state, 'page');
$form['displays']['page']['options']['items_per_page'] = array(
'#title' => t('Items per page'),
'#type' => 'textfield',
'#default_value' => '10',
'#size' => 5,
+ '#element_validate' => array('_element_validate_integer_positive'),
);
$form['displays']['page']['options']['link'] = array(
'#title' => t('Create a menu link'),
@@ -226,24 +230,27 @@ class ViewsUiBaseViewsWizard implements ViewsWizardInterface {
'#type' => 'fieldset',
'#attributes' => array('class' => array('container-inline')),
);
- // This may change by AJAX as we change the base table of the selected wizard.
+
+ // Create the dropdown for choosing the display format.
$form['displays']['block']['options']['style']['style_plugin'] = array(
'#title' => t('Display format'),
'#help_topic' => 'style',
'#type' => 'select',
'#options' => $style_options,
- '#default_value' => 'default',
- '#ajax' => array(
- 'callback' => 'views_ui_add_form_update_style_block',
- 'wrapper' => 'edit-block-style-plugin',
- ),
);
+ $style_form = &$form['displays']['block']['options']['style'];
+ $style_form['style_plugin']['#default_value'] = views_ui_get_selected($form_state, array('block', 'style', 'style_plugin'), 'default', $style_form['style_plugin']);
+ // Changing this dropdown updates $form['displays']['block']['options'] via
+ // AJAX.
+ views_ui_add_ajax_trigger($style_form, 'style_plugin', array('displays', 'block', 'options'));
+
$this->build_form_style($form, $form_state, 'block');
$form['displays']['block']['options']['items_per_page'] = array(
'#title' => t('Items per page'),
'#type' => 'textfield',
'#default_value' => '5',
'#size' => 5,
+ '#element_validate' => array('_element_validate_integer_positive'),
);
return $form;
@@ -254,7 +261,7 @@ class ViewsUiBaseViewsWizard implements ViewsWizardInterface {
*/
protected function build_form_style(&$form, &$form_state, $type) {
$style_form =& $form['displays'][$type]['options']['style'];
- $style = isset($form_state['values'][$type]) ? $form_state['values'][$type]['style']['style_plugin'] : 'default';
+ $style = $style_form['style_plugin']['#default_value'];
$style_plugin = views_get_plugin('style', $style);
if (isset($style_plugin) && $style_plugin->uses_row_plugin()) {
$options = $this->row_style_options($type);
@@ -262,14 +269,16 @@ class ViewsUiBaseViewsWizard implements ViewsWizardInterface {
'#type' => 'select',
'#title' => t('of'),
'#options' => $options,
- '#ajax' => array(
- 'wrapper' => "edit-style-$type-options-style-row-plugin-options",
- 'callback' => 'views_ui_add_form_update_row_' . $type,
- ),
+ '#access' => count($options) > 1,
);
+ $style_form['row_plugin']['#default_value'] = views_ui_get_selected($form_state, array($type, 'style', 'row_plugin'), key($options), $style_form['row_plugin']);
+ // Changing this dropdown updates the individual row options via AJAX.
+ views_ui_add_ajax_trigger($style_form, 'row_plugin', array('displays', $type, 'options', 'style', 'row_options'));
+
+ // This is the region that can be updated by AJAX. The base class doesn't
+ // add anything here, but child classes can.
$style_form['row_options'] = array(
'#theme_wrappers' => array('container'),
- '#attributes' => array('id' => "edit-style-$type-options-style-row-plugin-options"),
);
}
}
@@ -281,7 +290,7 @@ class ViewsUiBaseViewsWizard implements ViewsWizardInterface {
*/
protected function row_style_options($type) {
$data = views_fetch_data($this->base_table);
- // Get all availible availible row plugins by default.
+ // Get all available row plugins by default.
$options = views_fetch_plugin_names('row', 'normal', array($this->base_table));
return $options;
}
@@ -308,17 +317,13 @@ class ViewsUiBaseViewsWizard implements ViewsWizardInterface {
'#type' => 'select',
'#title' => t('of type'),
'#options' => $options,
- '#default_value' => 'all',
- '#ajax' => array(
- 'callback' => 'views_ui_add_form_update',
- 'wrapper' => 'edit-view-displays-wrapper',
- ),
);
- // Add this to the "Update options" button's form validation so the
- // submitted type will always be available in $form_state['values'].
- // This allows us to use $form_state['values']['show']['type'] to
- // dynamically build the rest of the form.
- $form['displays']['show']['update_wizard_key']['#limit_validation_errors'][] = array('show', 'type');
+ $selected_bundle = views_ui_get_selected($form_state, array('show', 'type'), 'all', $form['displays']['show']['type']);
+ $form['displays']['show']['type']['#default_value'] = $selected_bundle;
+ // Changing this dropdown updates the entire content of $form['displays']
+ // via AJAX, since each bundle might have entirely different fields
+ // attached to it, etc.
+ views_ui_add_ajax_trigger($form['displays']['show'], 'type', array('displays'));
}
// Check if we are allowed to filter by taxonomy, and if so, add the
@@ -343,13 +348,8 @@ class ViewsUiBaseViewsWizard implements ViewsWizardInterface {
// selected above, then we only search for taxonomy fields associated
// with that bundle. Otherwise, we use all bundles.
$bundles = array_keys($entity_info['bundles']);
- $selected_bundle = NULL;
- if (isset($form_state['values']['show']['type'])) {
- $selected_bundle = $form_state['values']['show']['type'];
- }
- elseif (isset($form['displays']['show']['type']['#default_value'])) {
- $selected_bundle = $form['displays']['show']['type']['#default_value'];
- }
+ // Double check that this is a real bundle before using it (since above
+ // we added a dummy option 'all' to the bundle list on the form).
if (isset($selected_bundle) && in_array($selected_bundle, $bundles)) {
$bundles = array($selected_bundle);
}
diff --git a/plugins/views_wizard/views_ui_comment_views_wizard.class.php b/plugins/views_wizard/views_ui_comment_views_wizard.class.php
index 18fe902..56ca53c 100644
--- a/plugins/views_wizard/views_ui_comment_views_wizard.class.php
+++ b/plugins/views_wizard/views_ui_comment_views_wizard.class.php
@@ -12,8 +12,13 @@ class ViewsUiCommentViewsWizard extends ViewsUiBaseViewsWizard {
protected function build_form_style(&$form, &$form_state, $type) {
parent::build_form_style($form, $form_state, $type);
$style_form =& $form['displays'][$type]['options']['style'];
- $row_style = isset($form_state['values'][$type]['style']['row_style']) ? $form_state['values'][$type]['style']['row_style'] : 'comment';
- switch ($row_style) {
+ // Some style plugins don't support row plugins so stop here if that's the
+ // case.
+ if (!isset($style_form['row_plugin'])) {
+ return;
+ }
+ $row_plugin = $style_form['row_plugin']['#default_value'];
+ switch ($row_plugin) {
case 'comment':
$style_form['row_options']['links'] = array(
'#type' => 'select',
@@ -30,17 +35,19 @@ class ViewsUiCommentViewsWizard extends ViewsUiBaseViewsWizard {
}
protected function page_display_options($form, $form_state) {
- $display_options = parent::default_display_options($form, $form_state);
- $row_plugin = $form_state['values']['page']['style']['row_plugin'];
- $row_options = $form_state['values']['page']['style']['row_options'];
+ $display_options = parent::page_display_options($form, $form_state);
+ $row_plugin = isset($form_state['values']['page']['style']['row_plugin']) ? $form_state['values']['page']['style']['row_plugin'] : NULL;
+ $row_options = isset($form_state['values']['page']['style']['row_options']) ? $form_state['values']['page']['style']['row_options'] : array();
$this->display_options_row($display_options, $row_plugin, $row_options);
+ return $display_options;
}
protected function block_display_options($form, $form_state) {
- $display_options = parent::default_display_options($form, $form_state);
- $row_plugin = $form_state['values']['block']['style']['row_plugin'];
- $row_options = $form_state['values']['block']['style']['row_options'];
+ $display_options = parent::block_display_options($form, $form_state);
+ $row_plugin = isset($form_state['values']['block']['style']['row_plugin']) ? $form_state['values']['block']['style']['row_plugin'] : NULL;
+ $row_options = isset($form_state['values']['block']['style']['row_options']) ? $form_state['values']['block']['style']['row_options'] : array();
$this->display_options_row($display_options, $row_plugin, $row_options);
+ return $display_options;
}
/**
diff --git a/plugins/views_wizard/views_ui_node_views_wizard.class.php b/plugins/views_wizard/views_ui_node_views_wizard.class.php
index 37f488e..86982ae 100644
--- a/plugins/views_wizard/views_ui_node_views_wizard.class.php
+++ b/plugins/views_wizard/views_ui_node_views_wizard.class.php
@@ -15,11 +15,12 @@ class ViewsUiNodeViewsWizard extends ViewsUiBaseViewsWizard {
protected function build_form_style(&$form, &$form_state, $type) {
parent::build_form_style($form, $form_state, $type);
$style_form =& $form['displays'][$type]['options']['style'];
- $row_plugin = isset($form_state['values'][$type]['style']['row_plugin']) ? $form_state['values'][$type]['style']['row_plugin'] : 'full_posts';
- // Some style plugins doesn't support row plugins so stop here and don't add some row plugins.
+ // Some style plugins don't support row plugins so stop here if that's the
+ // case.
if (!isset($style_form['row_plugin'])) {
return;
}
+ $row_plugin = $style_form['row_plugin']['#default_value'];
switch ($row_plugin) {
case 'full_posts':
case 'teasers':
@@ -79,7 +80,7 @@ class ViewsUiNodeViewsWizard extends ViewsUiBaseViewsWizard {
protected function page_display_options($form, $form_state) {
$display_options = parent::page_display_options($form, $form_state);
- $row_plugin = $form_state['values']['page']['style']['row_plugin'];
+ $row_plugin = isset($form_state['values']['page']['style']['row_plugin']) ? $form_state['values']['page']['style']['row_plugin'] : NULL;
$row_options = isset($form_state['values']['page']['style']['row_options']) ? $form_state['values']['page']['style']['row_options'] : array();
$this->display_options_row($display_options, $row_plugin, $row_options);
return $display_options;
@@ -87,7 +88,7 @@ class ViewsUiNodeViewsWizard extends ViewsUiBaseViewsWizard {
protected function block_display_options($form, $form_state) {
$display_options = parent::block_display_options($form, $form_state);
- $row_plugin = $form_state['values']['block']['style']['row_plugin'];
+ $row_plugin = isset($form_state['values']['block']['style']['row_plugin']) ? $form_state['values']['block']['style']['row_plugin'] : NULL;
$row_options = isset($form_state['values']['block']['style']['row_options']) ? $form_state['values']['block']['style']['row_options'] : array();
$this->display_options_row($display_options, $row_plugin, $row_options);
return $display_options;
@@ -107,7 +108,7 @@ class ViewsUiNodeViewsWizard extends ViewsUiBaseViewsWizard {
case 'teasers':
$display_options['row_plugin'] = 'node';
$display_options['row_options']['build_mode'] = 'teaser';
- $display_options['row_options']['links'] = !empty($row_options['links']);
+ $display_options['row_options']['links'] = !empty($row_options['links']);
$display_options['row_options']['comments'] = !empty($row_options['comments']);
break;
case 'titles_linked':
diff --git a/tests/views_ui.test b/tests/views_ui.test
index 67b3dd0..c772a72 100644
--- a/tests/views_ui.test
+++ b/tests/views_ui.test
@@ -342,7 +342,7 @@ class ViewsUIWizardTaggedWithTestCase extends ViewsUIWizardHelper {
// First select the node type and update the form so the correct tag field
// is used.
$view1['show[type]'] = $this->node_type_with_tags->type;
- $this->drupalPost('admin/structure/views/add', $view1, t('Update options'));
+ $this->drupalPost('admin/structure/views/add', $view1, t('Update "of type" choice'));
// Now resubmit the entire form to the same URL.
$view1['human_name'] = $this->randomName(16);
$view1['name'] = strtolower($this->randomName(16));
@@ -363,7 +363,7 @@ class ViewsUIWizardTaggedWithTestCase extends ViewsUIWizardHelper {
// the one node from above that is tagged with "tag2".
$view2 = array();
$view2['show[type]'] = $this->node_type_with_tags->type;
- $this->drupalPost('admin/structure/views/add', $view2, t('Update options'));
+ $this->drupalPost('admin/structure/views/add', $view2, t('Update "of type" choice'));
$view2['human_name'] = $this->randomName(16);
$view2['name'] = strtolower($this->randomName(16));
$view2['description'] = $this->randomName(16);
@@ -391,10 +391,10 @@ class ViewsUIWizardTaggedWithTestCase extends ViewsUIWizardHelper {
$this->drupalGet('admin/structure/views/add');
$this->assertFieldByXpath($tags_xpath);
$view['show[type]'] = $this->node_type_with_tags->type;
- $this->drupalPost('admin/structure/views/add', $view, t('Update options'));
+ $this->drupalPost('admin/structure/views/add', $view, t('Update "of type" choice'));
$this->assertFieldByXpath($tags_xpath);
$view['show[type]'] = $this->node_type_without_tags->type;
- $this->drupalPost(NULL, $view, t('Update options'));
+ $this->drupalPost(NULL, $view, t('Update "of type" choice'));
$this->assertNoFieldByXpath($tags_xpath);
// If we add an instance of the tagging field to the second node type, the
@@ -403,10 +403,10 @@ class ViewsUIWizardTaggedWithTestCase extends ViewsUIWizardHelper {
$instance['bundle'] = $this->node_type_without_tags->type;
field_create_instance($instance);
$view['show[type]'] = $this->node_type_with_tags->type;
- $this->drupalPost('admin/structure/views/add', $view, t('Update options'));
+ $this->drupalPost('admin/structure/views/add', $view, t('Update "of type" choice'));
$this->assertFieldByXpath($tags_xpath);
$view['show[type]'] = $this->node_type_without_tags->type;
- $this->drupalPost(NULL, $view, t('Update options'));
+ $this->drupalPost(NULL, $view, t('Update "of type" choice'));
$this->assertFieldByXpath($tags_xpath);
}
}