diff --git a/core/lib/Drupal/Core/Datetime/DateFormatter.php b/core/lib/Drupal/Core/Datetime/DateFormatter.php
index 0b4f817..88cb4f7 100644
--- a/core/lib/Drupal/Core/Datetime/DateFormatter.php
+++ b/core/lib/Drupal/Core/Datetime/DateFormatter.php
@@ -193,6 +193,33 @@ public function formatInterval($interval, $granularity = 2, $langcode = NULL) {
}
/**
+ * Provides values for all date formatting characters for a given timestamp.
+ *
+ * @param string|null $langcode
+ * (optional) Language code of the date format, if different from the site
+ * default language.
+ * @param int|null $timestamp
+ * (optional) The Unix timestamp to format. REQUEST_TIME is used by default.
+ * @param string|null $timezone
+ * (optional) The timezone to use, if different from the site's default
+ * timezone.
+ *
+ * @return array
+ * An array of formatted date values, indexed by the date format character.
+ *
+ * @see date()
+ */
+ public function getSampleDateFormats($langcode = NULL, $timestamp = NULL, $timezone = NULL) {
+ $timestamp = $timestamp ?: REQUEST_TIME;
+ // All date format characters for the PHP date() function.
+ $date_chars = str_split('dDjlNSwzWFmMntLoYyaABgGhHisueIOPTZcrU');
+ $date_elements = array_combine($date_chars, $date_chars);
+ return array_map(function($character) use ($timestamp, $timezone, $langcode) {
+ return $this->format($timestamp, 'custom', $character, $timezone, $langcode);
+ }, $date_elements);
+ }
+
+ /**
* Loads the given format pattern for the given langcode.
*
* @param string $format
@@ -200,10 +227,15 @@ public function formatInterval($interval, $granularity = 2, $langcode = NULL) {
* @param string $langcode
* The langcode of the language to use.
*
- * @return string
- * The pattern for the date format in the given language.
+ * @return string|null
+ * The pattern for the date format in the given language for
+ * non-custom formats, NULL otherwise.
+ *
*/
protected function dateFormat($format, $langcode) {
+ if ($format == 'custom') {
+ return NULL;
+ }
if (!isset($this->dateFormats[$format][$langcode])) {
$original_language = $this->languageManager->getConfigOverrideLanguage();
$this->languageManager->setConfigOverrideLanguage(new Language(array('id' => $langcode)));
@@ -226,4 +258,17 @@ protected function country() {
return $this->country;
}
+ /**
+ * Setter for country code.
+ *
+ * @param string $country_code
+ * String country code.
+ *
+ * @return $this
+ */
+ public function setCountryCode($country_code) {
+ $this->country = $country_code;
+ return $this;
+ }
+
}
diff --git a/core/modules/config_translation/src/Form/ConfigTranslationFormBase.php b/core/modules/config_translation/src/Form/ConfigTranslationFormBase.php
index 2831fd9..5bdbfc8 100644
--- a/core/modules/config_translation/src/Form/ConfigTranslationFormBase.php
+++ b/core/modules/config_translation/src/Form/ConfigTranslationFormBase.php
@@ -176,6 +176,9 @@ public function buildForm(array $form, FormStateInterface $form_state, Request $
if ($form_element = $this->createFormElement($schema)) {
$parents = array('config_names', $name);
$form['config_names'][$name] += $form_element->getTranslationBuild($this->sourceLanguage, $this->language, $source_config, $translation_config, $parents);
+ if ($attributes = $form_element->getFormAttributes()) {
+ $form = array_merge_recursive($form, $attributes);
+ }
}
}
diff --git a/core/modules/config_translation/src/FormElement/DateFormat.php b/core/modules/config_translation/src/FormElement/DateFormat.php
index 729afee..45aab74 100644
--- a/core/modules/config_translation/src/FormElement/DateFormat.php
+++ b/core/modules/config_translation/src/FormElement/DateFormat.php
@@ -22,51 +22,29 @@ class DateFormat extends FormElementBase {
* {@inheritdoc}
*/
public function getTranslationElement(LanguageInterface $translation_language, $source_config, $translation_config) {
+ /** @var \Drupal\Core\Datetime\DateFormatter $date_formatter */
+ $date_formatter = \Drupal::service('date.formatter');
$description = $this->t('A user-defined date format. See the PHP manual for available options.', array('@url' => 'http://php.net/manual/function.date.php'));
- $format = $this->t('Displayed as %date_format', array('%date_format' => \Drupal::service('date.formatter')->format(REQUEST_TIME, 'custom', $translation_config)));
+ $format = $this->t('Displayed as %date_format', array('%date_format' => $date_formatter->format(REQUEST_TIME, 'custom', $translation_config)));
- return array(
+ return [
'#type' => 'textfield',
'#description' => $description,
- '#field_suffix' => '
' . $format . '
',
- '#ajax' => array(
- 'callback' => 'Drupal\config_translation\FormElement\DateFormat::ajaxSample',
- 'event' => 'keyup',
- 'progress' => array('type' => 'throbber', 'message' => NULL),
- ),
- ) + parent::getTranslationElement($translation_language, $source_config, $translation_config);
+ '#field_suffix' => ' ' . $format . '',
+ '#attributes' => [
+ 'data-drupal-date-formatter' => 'source',
+ ],
+ '#attached' => [
+ 'drupalSettings' => array('dateFormats' => $date_formatter->getSampleDateFormats($translation_language->getId())),
+ ],
+ ] + parent::getTranslationElement($translation_language, $source_config, $translation_config);
}
/**
- * Ajax callback to render a sample of the input date format.
- *
- * @param array $form
- * Form API array structure.
- * @param \Drupal\Core\Form\FormStateInterface $form_state
- * Form state information.
- *
- * @return AjaxResponse
- * Ajax response with the rendered sample date using the given format. If
- * the given format cannot be identified or was empty, the response will
- * be empty as well.
+ * {@inheritdoc}
*/
- public static function ajaxSample(array $form, FormStateInterface $form_state) {
- $response = new AjaxResponse();
-
- $format_value = NestedArray::getValue($form_state->getValues(), $form_state->getTriggeringElement()['#array_parents']);
- if (!empty($format_value)) {
- // Format the date with a custom date format with the given pattern.
- // The object is not instantiated in an Ajax context, so $this->t()
- // cannot be used here.
- $format = t('Displayed as %date_format', array('%date_format' => \Drupal::service('date.formatter')->format(REQUEST_TIME, 'custom', $format_value)));
-
- // Return a command instead of a string, since the Ajax framework
- // automatically prepends an additional empty DIV element for a string,
- // which breaks the layout.
- $response->addCommand(new ReplaceCommand('#edit-date-format-suffix', '' . $format . ''));
- }
-
- return $response;
+ public function getFormAttributes() {
+ return ['#attached' => ['library' => ['system/drupal.system.date']]];
}
}
diff --git a/core/modules/config_translation/src/FormElement/ElementInterface.php b/core/modules/config_translation/src/FormElement/ElementInterface.php
index 286eeba..e58ce86 100644
--- a/core/modules/config_translation/src/FormElement/ElementInterface.php
+++ b/core/modules/config_translation/src/FormElement/ElementInterface.php
@@ -70,4 +70,12 @@ public function getTranslationBuild(LanguageInterface $source_language, Language
*/
public function setConfig(Config $base_config, LanguageConfigOverride $config_translation, $config_values, $base_key = NULL);
+ /**
+ * Allows providing form attributes for the configuration form.
+ *
+ * @return array
+ * An array of form attributes.
+ */
+ public function getFormAttributes();
+
}
diff --git a/core/modules/config_translation/src/FormElement/FormElementBase.php b/core/modules/config_translation/src/FormElement/FormElementBase.php
index 7db01e1..1ee5e77 100644
--- a/core/modules/config_translation/src/FormElement/FormElementBase.php
+++ b/core/modules/config_translation/src/FormElement/FormElementBase.php
@@ -75,6 +75,13 @@ public function getTranslationBuild(LanguageInterface $source_language, Language
}
/**
+ * {@inheritdoc}
+ */
+ public function getFormAttributes() {
+ return [];
+ }
+
+ /**
* Returns the source element for a given configuration definition.
*
* This can be either a render array that actually outputs the source values
diff --git a/core/modules/config_translation/src/FormElement/ListElement.php b/core/modules/config_translation/src/FormElement/ListElement.php
index 9365fc2..4723203 100644
--- a/core/modules/config_translation/src/FormElement/ListElement.php
+++ b/core/modules/config_translation/src/FormElement/ListElement.php
@@ -97,6 +97,23 @@ public function setConfig(Config $base_config, LanguageConfigOverride $config_tr
}
/**
+ * {@inheritdoc}
+ */
+ public function getFormAttributes() {
+ $attributes = [];
+ foreach ($this->element as $key => $element) {
+ if ($form_element = ConfigTranslationFormBase::createFormElement($element)) {
+ $form_attributes = $form_element->getFormAttributes();
+ if (empty($form_attributes)) {
+ continue;
+ }
+ $attributes += $form_attributes;
+ }
+ }
+ return $attributes;
+ }
+
+ /**
* Returns the title for the 'details' element of a group of schema elements.
*
* For some configuration elements the same element structure can be repeated
diff --git a/core/modules/system/js/system.date.js b/core/modules/system/js/system.date.js
new file mode 100644
index 0000000..fcab3ef
--- /dev/null
+++ b/core/modules/system/js/system.date.js
@@ -0,0 +1,46 @@
+(function ($, Drupal, drupalSettings) {
+
+ "use strict";
+
+ var dateFormats = drupalSettings.dateFormats;
+
+ /**
+ * Display the preview for date format entered.
+ */
+ Drupal.behaviors.dateFormat = {
+ attach: function (context) {
+ var $context = $(context);
+ var $source = $context.find('[data-drupal-date-formatter="source"]').once('dateFormat');
+ var $target = $context.find('[data-drupal-date-formatter="preview"]').once('dateFormat');
+ var $preview = $target.find('em');
+
+ // All elements have to exist.
+ if (!$source.length || !$target.length) {
+ return;
+ }
+
+ /**
+ * Event handler that replaces date characters with value.
+ *
+ * @param {object} e
+ */
+ function dateFormatHandler(e) {
+ var baseValue = $(e.target).val() || '';
+ var dateString = baseValue.replace(/\\?(.?)/gi, function (key, value) {
+ return dateFormats[key] ? dateFormats[key] : value;
+ });
+
+ $preview.html(dateString);
+ $target.toggleClass('js-hide', !dateString.length);
+ }
+
+ /**
+ * On given event triggers the date character replacement.
+ */
+ $source.on('keyup.dateFormat change.dateFormat input.dateFormat', dateFormatHandler)
+ // Initialize preview.
+ .trigger('keyup');
+ }
+ };
+
+})(jQuery, Drupal, drupalSettings);
diff --git a/core/modules/system/system.js b/core/modules/system/js/system.js
similarity index 100%
rename from core/modules/system/system.js
rename to core/modules/system/js/system.js
diff --git a/core/modules/system/system.modules.js b/core/modules/system/js/system.modules.js
similarity index 100%
rename from core/modules/system/system.modules.js
rename to core/modules/system/js/system.modules.js
diff --git a/core/modules/system/src/Form/DateFormatEditForm.php b/core/modules/system/src/Form/DateFormatEditForm.php
index f8e780f..511ad1a 100644
--- a/core/modules/system/src/Form/DateFormatEditForm.php
+++ b/core/modules/system/src/Form/DateFormatEditForm.php
@@ -21,7 +21,7 @@ public function form(array $form, FormStateInterface $form_state) {
$form = parent::form($form, $form_state);
$now = t('Displayed as %date', array('%date' => $this->dateFormatter->format(REQUEST_TIME, $this->entity->id())));
- $form['date_format_pattern']['#field_suffix'] = ' ' . $now . '';
+ $form['date_format_pattern']['#field_suffix'] = ' ' . $now . '';
$form['date_format_pattern']['#default_value'] = $this->entity->getPattern();
return $form;
diff --git a/core/modules/system/src/Form/DateFormatFormBase.php b/core/modules/system/src/Form/DateFormatFormBase.php
index c843ba2..9061d89 100644
--- a/core/modules/system/src/Form/DateFormatFormBase.php
+++ b/core/modules/system/src/Form/DateFormatFormBase.php
@@ -80,30 +80,6 @@ public function exists($entity_id, array $element) {
}
/**
- * Returns the date for a given format string.
- *
- * @param array $form
- * An associative array containing the structure of the form.
- * @param \Drupal\Core\Form\FormStateInterface $form_state
- * The current state of the form.
- *
- * @return \Drupal\Core\Ajax\AjaxResponse
- * An AJAX Response to update the date-time value of the date format.
- */
- public static function dateTimeLookup(array $form, FormStateInterface $form_state) {
- $format = '';
- if (!$form_state->isValueEmpty('date_format_pattern')) {
- $format = t('Displayed as %date_format', array('%date_format' => \Drupal::service('date.formatter')->format(REQUEST_TIME, 'custom', $form_state->getValue('date_format_pattern'))));
- }
- // Return a command instead of a string, since the Ajax framework
- // automatically prepends an additional empty DIV element for a string, which
- // breaks the layout.
- $response = new AjaxResponse();
- $response->addCommand(new ReplaceCommand('#edit-date-format-suffix', '' . $format . ''));
- return $response;
- }
-
- /**
* {@inheritdoc}
*/
public function form(array $form, FormStateInterface $form_state) {
@@ -126,20 +102,16 @@ public function form(array $form, FormStateInterface $form_state) {
'error' => $this->t('The machine-readable name must be unique, and can only contain lowercase letters, numbers, and underscores. Additionally, it can not be the reserved word "custom".'),
),
);
-
$form['date_format_pattern'] = array(
'#type' => 'textfield',
'#title' => t('Format string'),
'#maxlength' => 100,
'#description' => $this->t('A user-defined date format. See the PHP manual for available options.', array('@url' => 'http://php.net/manual/function.date.php')),
- '#default_value' => '',
- '#field_suffix' => ' ',
- '#ajax' => array(
- 'callback' => '::dateTimeLookup',
- 'event' => 'keyup',
- 'progress' => array('type' => 'throbber', 'message' => NULL),
- ),
'#required' => TRUE,
+ '#attributes' => [
+ 'data-drupal-date-formatter' => 'source',
+ ],
+ '#field_suffix' => ' ' . $this->t('Displayed as %date_format', ['%date_format' => '']) . '',
);
$form['langcode'] = array(
@@ -148,7 +120,8 @@ public function form(array $form, FormStateInterface $form_state) {
'#languages' => LanguageInterface::STATE_ALL,
'#default_value' => $this->entity->language()->getId(),
);
-
+ $form['#attached']['drupalSettings']['dateFormats'] = $this->dateFormatter->getSampleDateFormats();
+ $form['#attached']['library'][] = 'system/drupal.system.date';
return parent::form($form, $form_state);
}
diff --git a/core/modules/system/system.libraries.yml b/core/modules/system/system.libraries.yml
index 34c90dd..b440e15 100644
--- a/core/modules/system/system.libraries.yml
+++ b/core/modules/system/system.libraries.yml
@@ -29,7 +29,7 @@ maintenance:
drupal.system:
version: VERSION
js:
- system.js: {}
+ js/system.js: {}
dependencies:
- core/jquery
- core/drupal
@@ -39,7 +39,7 @@ drupal.system:
drupal.system.modules:
version: VERSION
js:
- system.modules.js: {}
+ js/system.modules.js: {}
dependencies:
- core/jquery
- core/drupal
@@ -50,3 +50,14 @@ diff:
css:
component:
css/system.diff.css: {}
+
+drupal.system.date:
+ version: VERSION
+ js:
+ js/system.date.js: {}
+ dependencies:
+ - core/jquery
+ - core/drupal
+ - core/drupalSettings
+ - core/jquery.once
+ - core/drupal.form
diff --git a/core/tests/Drupal/Tests/Core/Datetime/DateTest.php b/core/tests/Drupal/Tests/Core/Datetime/DateTest.php
index da9ebaa..575af07 100644
--- a/core/tests/Drupal/Tests/Core/Datetime/DateTest.php
+++ b/core/tests/Drupal/Tests/Core/Datetime/DateTest.php
@@ -5,9 +5,10 @@
* Contains \Drupal\Tests\Core\Datetime\DateTest.
*/
-namespace Drupal\Tests\Core\Datetime;
+namespace Drupal\Tests\Core\Datetime {
use Drupal\Core\Datetime\DateFormatter;
+use Drupal\Core\DependencyInjection\ContainerBuilder;
use Drupal\Tests\UnitTestCase;
/**
@@ -45,6 +46,7 @@ class DateTest extends UnitTestCase {
protected $dateFormatter;
protected function setUp() {
+ parent::setUp();
$this->entityManager = $this->getMock('Drupal\Core\Entity\EntityManagerInterface');
$this->languageManager = $this->getMock('Drupal\Core\Language\LanguageManagerInterface');
$this->stringTranslation = $this->getMock('Drupal\Core\StringTranslation\TranslationInterface');
@@ -128,4 +130,37 @@ public function testFormatIntervalZeroSecond() {
$this->assertEquals('0 sec', $result);
}
+ /**
+ * Tests the getSampleDateFormats method.
+ *
+ * @see \Drupal\Core\Datetime\DateFormatter::getSampleDateFormats()
+ */
+ public function testGetSampleDateFormats() {
+ include_once $this->root . '/core/includes/common.inc';
+ $ts = strtotime('2015-03-22 14:23:00');
+ $this->dateFormatter->setCountryCode('GB');
+ $expected = $this->dateFormatter->getSampleDateFormats('en', $ts, 'Europe/London');
+
+ // Removed characters related to timezone 'e' and 'T', as test
+ // does not have timezone set.
+ $date_characters = 'dDjlNSwzWFmMntLoYyaABgGhHisuIOPZcrU';
+ $date_chars = str_split($date_characters);
+
+ foreach ($date_chars as $val) {
+ $this->assertEquals($expected[$val], date($val, $ts));
+ }
+ }
+
+}
+
+}
+
+namespace {
+ use Drupal\Component\Utility\String;
+
+ if (!function_exists('t')) {
+ function t($string, array $args = []) {
+ return String::format($string, $args);
+ }
+ }
}