commit f709bc19b0ddc3984f032e5360a579de565cfc7d
Author: Jonathan Sacksick <jonathan.sacksick@gmail.com>
Date:   Fri May 11 11:53:10 2018 +0300

    Issue #2838457: Re-enable the default value functionality.

diff --git a/address.install b/address.install
index a583aad..537a23d 100644
--- a/address.install
+++ b/address.install
@@ -1,5 +1,6 @@
 <?php
 
+use Drupal\Core\Entity\Entity\EntityFormDisplay;
 use Drupal\Core\Entity\Sql\SqlContentEntityStorage;
 use Drupal\Core\Entity\Sql\SqlContentEntityStorageException;
 use Drupal\Core\Utility\UpdateException;
@@ -199,3 +200,41 @@ function address_update_8103() {
     $config_factory->getEditable($name)->delete();
   }
 }
+
+/**
+ * Transfers the default country code widget setting to the field config.
+ */
+function address_update_8104() {
+  $entity_field_manager = \Drupal::service('entity_field.manager');
+  $entity_field_map = $entity_field_manager->getFieldMapByFieldType('address');
+  foreach ($entity_field_map as $entity_type_id => $fields) {
+    foreach ($fields as $field_name => $field_info) {
+      foreach ($field_info['bundles'] as $bundle) {
+        $field = FieldConfig::loadByName($entity_type_id, $bundle, $field_name);
+        if (!$field) {
+          // This is a base field, nothing can be done.
+          continue 2;
+        }
+        $form_display = EntityFormDisplay::load("$entity_type_id.$bundle.default");
+        $address_component = $form_display->getComponent($field_name);
+        if (!empty($address_component['settings']['default_country'])) {
+          $country_code = $address_component['settings']['default_country'];
+        }
+        else {
+          $country_code = \Drupal::config('system.date')->get('country.default');
+          $country_code = $country_code ?: 'US';
+        }
+        // Remove the default_country setting.
+        $address_component['settings'] = [];
+        $form_display->setComponent($field_name, $address_component);
+        $form_display->save();
+        $field->setDefaultValue([
+          [
+            'country_code' => $country_code,
+          ]
+        ]);
+        $field->save();
+      }
+    }
+  }
+}
diff --git a/address.module b/address.module
index 239590a..ebbd50d 100644
--- a/address.module
+++ b/address.module
@@ -5,24 +5,6 @@
  * Provides functionality for handling postal addresses.
  */
 
-use Drupal\Core\Form\FormStateInterface;
-
-/**
- * Implements hook_form_BASE_FORM_ID_alter().
- *
- * Removes the default values form from the field settings page.
- * Users expect to use the default value form to predefine only certain values
- * on the widget, but Drupal expects the default value to be complete, and used
- * whenever an actual address isn't provided. Therefore it's preferable to
- * hide this functionality and implement our own via custom widget settings.
- */
-function address_form_field_config_edit_form_alter(&$form, FormStateInterface $form_state) {
-  $field = $form_state->getFormObject()->getEntity();
-  if ($field->getType() == 'address') {
-    $form['default_value']['#access'] = FALSE;
-  }
-}
-
 /**
  * Implements hook_theme().
  */
diff --git a/config/schema/address.schema.yml b/config/schema/address.schema.yml
index 7f8cf16..2255723 100644
--- a/config/schema/address.schema.yml
+++ b/config/schema/address.schema.yml
@@ -134,10 +134,6 @@ field.field_settings.address_zone:
 field.widget.settings.address_default:
   type: mapping
   label: 'Default address widget settings'
-  mapping:
-    default_country:
-      type: string
-      label: 'Default country'
 
 field.widget.settings.address_zone_default:
   type: mapping
diff --git a/src/Plugin/Field/FieldType/AddressFieldItemList.php b/src/Plugin/Field/FieldType/AddressFieldItemList.php
new file mode 100644
index 0000000..c5451a5
--- /dev/null
+++ b/src/Plugin/Field/FieldType/AddressFieldItemList.php
@@ -0,0 +1,20 @@
+<?php
+
+namespace Drupal\address\Plugin\Field\FieldType;
+
+use Drupal\Core\Field\FieldItemList;
+use Drupal\Core\Form\FormStateInterface;
+
+/**
+ * Defines a item list class for Address fields.
+ */
+class AddressFieldItemList extends FieldItemList {
+
+  /**
+   * {@inheritdoc}
+   */
+  public function defaultValuesFormValidate(array $element, array &$form, FormStateInterface $form_state) {
+    // Skip the validation on the default value form.
+  }
+
+}
diff --git a/src/Plugin/Field/FieldType/AddressItem.php b/src/Plugin/Field/FieldType/AddressItem.php
index 2ccfa6b..ed6578b 100644
--- a/src/Plugin/Field/FieldType/AddressItem.php
+++ b/src/Plugin/Field/FieldType/AddressItem.php
@@ -20,7 +20,8 @@ use Drupal\Core\TypedData\DataDefinition;
  *   description = @Translation("An entity field containing a postal address"),
  *   category = @Translation("Address"),
  *   default_widget = "address_default",
- *   default_formatter = "address_default"
+ *   default_formatter = "address_default",
+ *   list_class = "\Drupal\address\Plugin\Field\FieldType\AddressFieldItemList"
  * )
  */
 class AddressItem extends FieldItemBase implements AddressInterface {
diff --git a/src/Plugin/Field/FieldWidget/AddressDefaultWidget.php b/src/Plugin/Field/FieldWidget/AddressDefaultWidget.php
index 31ebb68..72d0768 100644
--- a/src/Plugin/Field/FieldWidget/AddressDefaultWidget.php
+++ b/src/Plugin/Field/FieldWidget/AddressDefaultWidget.php
@@ -12,6 +12,7 @@ use Drupal\Core\Field\WidgetBase;
 use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Field\FieldDefinitionInterface;
 use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
+use Drupal\Core\Render\Element;
 use Symfony\Component\DependencyInjection\ContainerInterface;
 use Symfony\Component\EventDispatcher\EventDispatcherInterface;
 use Symfony\Component\Validator\ConstraintViolationInterface;
@@ -95,98 +96,12 @@ class AddressDefaultWidget extends WidgetBase implements ContainerFactoryPluginI
     );
   }
 
-  /**
-   * {@inheritdoc}
-   */
-  public static function defaultSettings() {
-    return [
-      'default_country' => NULL,
-    ] + parent::defaultSettings();
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function settingsForm(array $form, FormStateInterface $form_state) {
-    $country_list = $this->countryRepository->getList();
-    $element = [];
-    $element['default_country'] = [
-      '#type' => 'select',
-      '#title' => $this->t('Default country'),
-      '#options' => ['site_default' => $this->t('- Site default -')] + $country_list,
-      '#default_value' => $this->getSetting('default_country'),
-      '#empty_value' => '',
-    ];
-
-    return $element;
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function settingsSummary() {
-    $default_country = $this->getSetting('default_country');
-    if (empty($default_country)) {
-      $default_country = $this->t('None');
-    }
-    elseif ($default_country == 'site_default') {
-      $default_country = $this->t('Site default');
-    }
-    else {
-      $country_list = $this->countryRepository->getList();
-      $default_country = $country_list[$default_country];
-    }
-    $summary = [];
-    $summary['default_country'] = $this->t('Default country: @country', ['@country' => $default_country]);
-
-    return $summary;
-  }
-
-  /**
-   * Gets the initial values for the widget.
-   *
-   * This is a replacement for the disabled default values functionality.
-   *
-   * @see address_form_field_config_edit_form_alter()
-   *
-   * @return array
-   *   The initial values, keyed by property.
-   */
-  protected function getInitialValues() {
-    $default_country = $this->getSetting('default_country');
-    // Resolve the special site_default option.
-    if ($default_country == 'site_default') {
-      $default_country = $this->configFactory->get('system.date')->get('country.default');
-    }
-
-    $initial_values = [
-      'country_code' => $default_country,
-      'administrative_area' => '',
-      'locality' => '',
-      'dependent_locality' => '',
-      'postal_code' => '',
-      'sorting_code' => '',
-      'address_line1' => '',
-      'address_line2' => '',
-      'organization' => '',
-      'given_name' => '',
-      'additional_name' => '',
-      'family_name' => '',
-    ];
-    // Allow other modules to alter the values.
-    $event = new InitialValuesEvent($initial_values, $this->fieldDefinition);
-    $this->eventDispatcher->dispatch(AddressEvents::INITIAL_VALUES, $event);
-    $initial_values = $event->getInitialValues();
-
-    return $initial_values;
-  }
-
   /**
    * {@inheritdoc}
    */
   public function formElement(FieldItemListInterface $items, $delta, array $element, array &$form, FormStateInterface $form_state) {
     $item = $items[$delta];
-    $value = $item->getEntity()->isNew() ? $this->getInitialValues() : $item->toArray();
+    $value = $item->toArray();
     // Calling initializeLangcode() every time, and not just when the field
     // is empty, ensures that the langcode can be changed on subsequent
     // edits (because the entity or interface language changed, for example).
@@ -205,6 +120,10 @@ class AddressDefaultWidget extends WidgetBase implements ContainerFactoryPluginI
       '#used_fields' => $this->getFieldSetting('fields'),
     ];
 
+    if ($form_state->has('default_value_widget')) {
+      $element['address']['#after_build'] = [[get_class($this), 'makeFieldsOptional']];
+    }
+
     return $element;
   }
 
@@ -227,4 +146,17 @@ class AddressDefaultWidget extends WidgetBase implements ContainerFactoryPluginI
     return $new_values;
   }
 
+  /**
+   * Form API callback: Makes address fields optional when rendered inside the
+   * default value form.
+   */
+  public static function makeFieldsOptional($element, FormStateInterface $form_state) {
+    foreach (Element::getVisibleChildren($element) as $key) {
+      if (!empty($element[$key]['#required'])) {
+        $element[$key]['#required'] = FALSE;
+      }
+    }
+    return $element;
+  }
+
 }
diff --git a/tests/src/FunctionalJavascript/AddressDefaultWidgetTest.php b/tests/src/FunctionalJavascript/AddressDefaultWidgetTest.php
index 7dee2c1..8c7850c 100644
--- a/tests/src/FunctionalJavascript/AddressDefaultWidgetTest.php
+++ b/tests/src/FunctionalJavascript/AddressDefaultWidgetTest.php
@@ -118,6 +118,11 @@ class AddressDefaultWidgetTest extends JavascriptTestBase {
       'field_storage' => $field_storage,
       'bundle' => 'article',
       'label' => 'Address',
+      'default_value' => [
+        [
+          'country_code' => 'US',
+        ],
+      ],
     ]);
     $this->field->save();
 
@@ -135,9 +140,6 @@ class AddressDefaultWidgetTest extends JavascriptTestBase {
     }
     $this->formDisplay->setComponent($this->field->getName(), [
       'type' => 'address_default',
-      'settings' => [
-        'default_country' => 'US',
-      ],
     ])->save();
 
     $this->nodeAddUrl = 'node/add/article';
@@ -153,7 +155,6 @@ class AddressDefaultWidgetTest extends JavascriptTestBase {
    *
    * Checked:
    * - required/optional status.
-   * - default_country widget setting.
    * - available_countries instance setting.
    */
   public function testCountries() {
@@ -263,50 +264,6 @@ class AddressDefaultWidgetTest extends JavascriptTestBase {
     $this->assertSession()->fieldValueEquals($field_name . '[0][address][postal_code]', $address['postal_code']);
   }
 
-  /**
-   * Tests the initial values and available countries alter events.
-   */
-  public function testEvents() {
-    $field_name = $this->field->getName();
-    // The address_test module is installed here, not in setUp().
-    // This way the module's events will not affect other tests.
-    self::$modules[] = 'address_test';
-    $this->container->get('module_installer')->install(self::$modules);
-    $this->container = $this->kernel->rebuildContainer();
-    // Get available countries and initial values from module's event subscriber.
-    $subscriber = \Drupal::service('address_test.event_subscriber');
-    $available_countries = array_keys($subscriber->getAvailableCountries());
-    $initial_values = $subscriber->getInitialValues();
-    // Access the content add form and test the list of countries.
-    $this->drupalGet($this->nodeAddUrl);
-    $this->assertOptions($field_name . '[0][address][country_code]', $available_countries, 'Available countries set in the event subscriber are present in the widget.');
-    // Test the values of the fields.
-    foreach ($initial_values as $key => $value) {
-      if ($value) {
-        $name = $field_name . '[0][address][' . $key . ']';
-        $this->assertSession()->fieldValueEquals($name, $value);
-      }
-    }
-    // Test the GB counties.
-    $expected_counties = [
-      'Anglesey', 'Blaenau Gwent', 'Bridgend', 'Caerphilly', 'Cardiff',
-      'Carmarthenshire', 'Ceredigion', 'Conwy', 'Denbighshire', 'Flintshire',
-      'Gwynedd', 'Merthyr Tydfil', 'Monmouthshire', 'Neath Port Talbot',
-      'Newport', 'Pembrokeshire', 'Powys', 'Rhondda Cynon Taf', 'Swansea',
-      'Tarfaen', 'Vale of Glamorgan', 'Wrexham',
-    ];
-    $this->drupalGet($this->nodeAddUrl);
-    $this->getSession()->getPage()->fillField($field_name . '[0][address][country_code]', 'GB');
-    $this->waitForAjaxToFinish();
-    $this->assertSession()->pageTextContains(t('County'));
-    $this->assertSession()->fieldExists($field_name . '[0][address][administrative_area]');
-    $this->assertOptions($field_name . '[0][address][administrative_area]', $expected_counties);
-    // Uninstall and remove the address_test module.
-    $this->container->get('module_installer')->uninstall(['address_test']);
-    $this->container = $this->kernel->rebuildContainer();
-    array_pop(self::$modules);
-  }
-
   /**
    * Tests expected and disabled fields.
    */
