diff --git a/modules/order/src/Element/ProfileSelect.php b/modules/order/src/Element/ProfileSelect.php index 0f36739..de5b3e5 100644 --- a/modules/order/src/Element/ProfileSelect.php +++ b/modules/order/src/Element/ProfileSelect.php @@ -6,6 +6,7 @@ use Drupal\Component\Utility\Html; use Drupal\Component\Utility\NestedArray; use Drupal\Core\Entity\Entity\EntityFormDisplay; +use Drupal\Core\Form\FormState; use Drupal\Core\Form\FormStateInterface; use Drupal\Core\Render\Element\RenderElement; use Drupal\profile\Entity\ProfileInterface; @@ -70,9 +71,6 @@ public function getInfo() { [$class, 'validateElementSubmit'], [$class, 'validateForm'], ], - '#commerce_element_submit' => [ - [$class, 'submitForm'], - ], '#theme_wrappers' => ['container'], ]; } @@ -123,7 +121,7 @@ public static function validateElementProperties(array $element) { public static function processElement(array $element, FormStateInterface $form_state, array &$complete_form) { self::validateElementProperties($element); - $element_state = self::getElementState($element['#parents'], $form_state, ['mode' => 'view']); + $element_state = self::getElementState($element['#parents'], $form_state); // If the provided profile is in a previous revision, make sure it stays // available as an option when $element['#profile'] gets changed. if (empty($element['#profile_latest_revision']) && empty($element_state['fixed_option'])) { @@ -160,7 +158,7 @@ public static function processElement(array $element, FormStateInterface $form_s // where to return the customer upon cancelling form mode. $element_state['selected_option'] = $selected_option; } - elseif (!empty($element_state['selected_option'])) { + elseif (!empty($element_state['selected_option']) && !$form_state->get('cancel_profile')) { $selected_option = $element_state['selected_option']; } else { @@ -170,7 +168,7 @@ public static function processElement(array $element, FormStateInterface $form_s } } - if ($selected_option == '_new') { + if ($selected_option == '_new' && !$form_state->get('cancel_profile')) { $element['#profile'] = $profile_storage->create([ 'type' => $element['#profile_type'], 'uid' => $element['#profile_uid'], @@ -186,15 +184,16 @@ public static function processElement(array $element, FormStateInterface $form_s $element['#profile'] = $profile_storage->load($id_parts[0]); } } + $form_state->set('cancel_profile', FALSE); $id_prefix = implode('-', $element['#parents']); $wrapper_id = Html::getUniqueId($id_prefix . '-ajax-wrapper'); $element = [ - '#prefix' => '
', - '#suffix' => '
', - // Pass the id along to other methods. - '#wrapper_id' => $wrapper_id, - ] + $element; + '#prefix' => '
', + '#suffix' => '
', + // Pass the id along to other methods. + '#wrapper_id' => $wrapper_id, + ] + $element; if ($element_state['mode'] == 'view') { $element['profile_selection'] = [ @@ -206,9 +205,7 @@ public static function processElement(array $element, FormStateInterface $form_s 'callback' => [get_called_class(), 'ajaxRefresh'], 'wrapper' => $wrapper_id, ], - '#limit_validation_errors' => [ - array_merge($element['#parents'], ['profile_selection']), - ], + '#limit_validation_errors' => [], '#weight' => -1, '#access' => !empty($profile_options), ]; @@ -217,7 +214,7 @@ public static function processElement(array $element, FormStateInterface $form_s $element['profile'] = $view_builder->view($element['#profile'], 'default'); $element['edit_button'] = [ - '#type' => 'submit', + '#type' => 'button', '#value' => t('Edit'), '#limit_validation_errors' => [], '#ajax' => [ @@ -250,19 +247,54 @@ public static function processElement(array $element, FormStateInterface $form_s $widget_element['address']['#available_countries'] = $element['#available_countries']; } } - + // Create a dummy button so the triggering element is not a button that + // has real significance. See FormBuilder->doBuildForm logic around + // support for IE and setTriggeringElement. + $element['dummy'] = [ + '#type' => 'button', + '#value' => t('Dummy'), + '#attributes' => ['class' => ['visually-hidden']], + '#limit_validation_errors' => [], + '#ajax' => [ + 'callback' => [get_called_class(), 'ajaxRefresh'], + 'wrapper' => $wrapper_id, + ], + '#submit' => [ + [get_called_class(), 'ajaxSubmit'], + ], + ]; + $element['submit'] = [ + '#type' => 'submit', + '#value' => t('Save'), + '#ajax' => [ + 'callback' => [get_called_class(), 'ajaxRefresh'], + 'wrapper' => $wrapper_id, + ], + '#submit' => [ + [get_called_class(), 'ajaxSubmit'], + ], + '#name' => implode('_', $element['#parents']) . '_submit', + '#element_mode' => 'view', + '#save_profile' => TRUE, + '#access' => !empty($profiles), + '#button_type' => 'primary', + ]; $element['cancel_button'] = [ '#type' => 'submit', - '#value' => t('Return to address selection'), + '#value' => t('Cancel'), '#limit_validation_errors' => [], '#ajax' => [ 'callback' => [get_called_class(), 'ajaxRefresh'], 'wrapper' => $wrapper_id, ], - '#submit' => [[get_called_class(), 'ajaxSubmit']], + '#submit' => [ + [get_called_class(), 'ajaxSubmit'], + ], '#name' => implode('_', $element['#parents']) . '_cancel', '#element_mode' => 'view', + '#cancel' => TRUE, '#access' => !empty($profiles), + '#button_type' => 'danger', ]; } @@ -285,31 +317,21 @@ public static function processElement(array $element, FormStateInterface $form_s * form, as a protection against buggy behavior. */ public static function validateForm(array &$element, FormStateInterface $form_state) { - $element_state = self::getElementState($element['#parents'], $form_state, ['mode' => 'view']); - if ($element_state['mode'] == 'form') { + self::getElementMode($form_state); + $triggering_element = $form_state->getTriggeringElement(); + $form_state->set('save_profile', FALSE); + $form_state->set('cancel_profile', FALSE); + if (!empty($triggering_element['#save_profile']) && !empty($element['form'])) { $form_display = EntityFormDisplay::collectRenderDisplay($element['#profile'], 'default'); $form_display->extractFormValues($element['#profile'], $element['form'], $form_state); $form_display->validateFormValues($element['#profile'], $element['form'], $form_state); - } - } - - /** - * Submits the element form. - * - * @param array $element - * The form element. - * @param \Drupal\Core\Form\FormStateInterface $form_state - * The current state of the form. - */ - public static function submitForm(array &$element, FormStateInterface $form_state) { - $element_state = self::getElementState($element['#parents'], $form_state, ['mode' => 'view']); - if ($element_state['mode'] == 'form') { - $form_display = EntityFormDisplay::collectRenderDisplay($element['#profile'], 'default'); - $form_display->extractFormValues($element['#profile'], $element['form'], $form_state); - if ($element['#profile']->hasTranslationChanges()) { + if (!FormState::hasAnyErrors() && $element['#profile']->hasTranslationChanges()) { $element['#profile']->save(); } } + if (!empty($triggering_element['#cancel'])) { + $form_state->set('cancel_profile', TRUE); + } } /** @@ -374,32 +396,58 @@ public static function ajaxRefresh(array &$form, FormStateInterface $form_state) public static function ajaxSubmit(array &$form, FormStateInterface $form_state) { $triggering_element = $form_state->getTriggeringElement(); $element = NestedArray::getValue($form, array_slice($triggering_element['#array_parents'], 0, -1)); - $element_state = self::getElementState($element['#parents'], $form_state, ['mode' => 'view']); - $element_state['mode'] = $triggering_element['#element_mode']; + $element_state = self::getElementState($element['#parents'], $form_state); self::setElementState($element['#parents'], $form_state, $element_state); $form_state->setRebuild(); } /** + * Submits the element form. + * + * @param array $element + * The form element. + * @param \Drupal\Core\Form\FormStateInterface $form_state + * The current state of the form. + */ + public static function submitForm(array &$element, FormStateInterface $form_state) {} + + /** * Gets the element state. * * @param array $parents * The element parents. * @param \Drupal\Core\Form\FormStateInterface $form_state * The current state of the form. - * @param array $defaults - * The defaults. * * @return array * The element state. */ - public static function getElementState(array $parents, FormStateInterface $form_state, array $defaults) { + public static function getElementState(array $parents, FormStateInterface $form_state) { $parents = array_merge(['element_state', '#parents'], $parents); $element_state = (array) NestedArray::getValue($form_state->getStorage(), $parents); - return $element_state + $defaults; + $element_state['mode'] = self::getElementMode($form_state); + return $element_state; } /** + * Get the element mode. + * + * @param \Drupal\Core\Form\FormStateInterface $form_state + * The current state of the form. + * + * @return string + * The element mode. + */ + public static function getElementMode(FormStateInterface $form_state) { + $triggering_element = $form_state->getTriggeringElement(); + if (!empty($triggering_element['#element_mode'])) { + $form_state->set('element_mode', $triggering_element['#element_mode']); + } + return $form_state->get('element_mode') ?: 'view'; + } + + + /** * Sets the element state. * * @param array $parents