composer update
This commit is contained in:
parent
f6abc3dce2
commit
71dfaca858
1753 changed files with 45274 additions and 14619 deletions
|
@ -233,11 +233,11 @@ class WebformCliService implements WebformCliServiceInterface {
|
|||
/* Repair */
|
||||
|
||||
$items['webform-repair'] = [
|
||||
'description' => 'Makes sure all Webform admin settings and webforms are up-to-date.',
|
||||
'description' => 'Makes sure all Webform admin configuration and webform settings are up-to-date.',
|
||||
'core' => ['8+'],
|
||||
'bootstrap' => DRUSH_BOOTSTRAP_DRUPAL_ROOT,
|
||||
'examples' => [
|
||||
'webform-repair' => 'Repairs admin settings and webforms are up-to-date.',
|
||||
'webform-repair' => 'Repairs admin configuration and webform settings are up-to-date.',
|
||||
],
|
||||
'aliases' => ['wfr'],
|
||||
];
|
||||
|
@ -394,7 +394,8 @@ class WebformCliService implements WebformCliServiceInterface {
|
|||
|
||||
// Make sure there are submissions that need to be deleted.
|
||||
if (!$submission_storage->getTotal($webform)) {
|
||||
return $this->drush_set_error($this->dt('There are no submissions that need to be deleted.'));
|
||||
$this->drush_print($this->dt('There are no submissions that need to be deleted.'));
|
||||
return;
|
||||
}
|
||||
|
||||
if (!$webform) {
|
||||
|
@ -484,26 +485,40 @@ class WebformCliService implements WebformCliServiceInterface {
|
|||
$original_yaml = file_get_contents($file->uri);
|
||||
$tidied_yaml = $original_yaml;
|
||||
|
||||
// Add module dependency to exporter webform and webform options config entities.
|
||||
if ($dependencies && preg_match('/^(webform\.webform\.|webform\.webform_options\.)/', $file->filename)) {
|
||||
try {
|
||||
$data = Yaml::decode($tidied_yaml);
|
||||
}
|
||||
catch (\Exception $exception) {
|
||||
$message = 'Error parsing: ' . $file->filename . PHP_EOL . $exception->getMessage();
|
||||
if (strlen($message) > 255) {
|
||||
$message = substr($message, 0, 255) . '…';
|
||||
}
|
||||
$this->drush_log($message, LogLevel::ERROR);
|
||||
$this->drush_print($message);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Tidy elements.
|
||||
if (strpos($file->filename, 'webform.webform.') === 0 && isset($data['elements'])) {
|
||||
try {
|
||||
$data = Yaml::decode($tidied_yaml);
|
||||
if (empty($data['dependencies']['enforced']['module']) || !in_array($target, $data['dependencies']['enforced']['module'])) {
|
||||
$this->drush_print($this->dt('Adding module dependency to @file…', ['@file' => $file->filename]));
|
||||
$data['dependencies']['enforced']['module'][] = $target;
|
||||
$tidied_yaml = Yaml::encode($data);
|
||||
}
|
||||
$elements = WebformYaml::tidy($data['elements']);
|
||||
$data['elements'] = $elements;
|
||||
}
|
||||
catch (\Exception $exception) {
|
||||
$message = 'Error parsing: ' . $file->filename . PHP_EOL . $exception->getMessage();
|
||||
if (strlen($message) > 255) {
|
||||
$message = substr($message, 0, 255) . '…';
|
||||
}
|
||||
$this->drush_log($message, LogLevel::ERROR);
|
||||
$this->drush_print($message);
|
||||
// Do nothing.
|
||||
}
|
||||
}
|
||||
|
||||
// Add module dependency to exporter webform and webform options config entities.
|
||||
if ($dependencies && preg_match('/^(webform\.webform\.|webform\.webform_options\.)/', $file->filename)) {
|
||||
if (empty($data['dependencies']['enforced']['module']) || !in_array($target, $data['dependencies']['enforced']['module'])) {
|
||||
$this->drush_print($this->dt('Adding module dependency to @file…', ['@file' => $file->filename]));
|
||||
$data['dependencies']['enforced']['module'][] = $target;
|
||||
}
|
||||
}
|
||||
|
||||
$tidied_yaml = Yaml::encode($data);
|
||||
|
||||
// Tidy and add new line to the end of the tidied file.
|
||||
$tidied_yaml = WebformYaml::tidy($tidied_yaml) . PHP_EOL;
|
||||
if ($tidied_yaml != $original_yaml) {
|
||||
|
@ -639,6 +654,11 @@ class WebformCliService implements WebformCliServiceInterface {
|
|||
$libraries_manager = \Drupal::service('webform.libraries_manager');
|
||||
$libraries = $libraries_manager->getLibraries(TRUE);
|
||||
foreach ($libraries as $library_name => $library) {
|
||||
// Skip libraries installed by other modules.
|
||||
if (!empty($library['module'])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Download archive to temp directory.
|
||||
$download_url = $library['download_url']->toString();
|
||||
$this->drush_print("Downloading $download_url");
|
||||
|
@ -719,6 +739,8 @@ class WebformCliService implements WebformCliServiceInterface {
|
|||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* @see \Drupal\webform\Form\AdminConfig\WebformAdminConfigAdvancedForm::submitForm
|
||||
*/
|
||||
public function drush_webform_repair() {
|
||||
if (!$this->drush_confirm($this->dt("Are you sure you want repair the Webform module's admin settings and webforms?"))) {
|
||||
|
@ -727,23 +749,26 @@ class WebformCliService implements WebformCliServiceInterface {
|
|||
|
||||
module_load_include('install', 'webform');
|
||||
|
||||
$this->drush_print('Repairing admin settings…');
|
||||
$this->drush_print($this->dt('Repairing webform submission storage schema…'));
|
||||
_webform_update_webform_submission_storage_schema();
|
||||
|
||||
$this->drush_print($this->dt('Repairing admin settings…'));
|
||||
_webform_update_admin_settings(TRUE);
|
||||
|
||||
$this->drush_print('Repairing webform settings…');
|
||||
$this->drush_print($this->dt('Repairing webform settings…'));
|
||||
_webform_update_webform_settings();
|
||||
|
||||
$this->drush_print('Repairing webform handlers…');
|
||||
$this->drush_print($this->dt('Repairing webform handlers…'));
|
||||
_webform_update_webform_handler_settings();
|
||||
|
||||
$this->drush_print('Repairing webform field storage definitions…');
|
||||
$this->drush_print($this->dt('Repairing webform field storage definitions…'));
|
||||
_webform_update_field_storage_definitions();
|
||||
|
||||
$this->drush_print('Repairing webform submission storage schema…');
|
||||
$this->drush_print($this->dt('Repairing webform submission storage schema…'));
|
||||
_webform_update_webform_submission_storage_schema();
|
||||
|
||||
// Validate all webform elements.
|
||||
$this->drush_print('Validating webform elements…');
|
||||
$this->drush_print($this->dt('Validating webform elements…'));
|
||||
/** @var \Drupal\webform\WebformEntityElementsValidatorInterface $elements_validator */
|
||||
$elements_validator = \Drupal::service('webform.elements_validator');
|
||||
|
||||
|
@ -751,7 +776,7 @@ class WebformCliService implements WebformCliServiceInterface {
|
|||
$webforms = Webform::loadMultiple();
|
||||
foreach ($webforms as $webform) {
|
||||
if ($messages = $elements_validator->validate($webform)) {
|
||||
$this->drush_print(' ' . t('@title (@id): Found element validation errors.', ['@title' => $webform->label(), '@id' => $webform->id()]));
|
||||
$this->drush_print(' ' . $this->dt('@title (@id): Found element validation errors.', ['@title' => $webform->label(), '@id' => $webform->id()]));
|
||||
foreach ($messages as $message) {
|
||||
$this->drush_print(' - ' . strip_tags($message));
|
||||
}
|
||||
|
@ -1017,6 +1042,11 @@ class WebformCliService implements WebformCliServiceInterface {
|
|||
continue;
|
||||
}
|
||||
|
||||
// Skip libraries installed by other modules.
|
||||
if (!empty($library['module'])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$dist_url = $library['download_url']->toString();
|
||||
if (preg_match('/\.zip$/', $dist_url)) {
|
||||
$dist_type = 'zip';
|
||||
|
@ -1237,6 +1267,7 @@ $functions
|
|||
|
||||
// usage.
|
||||
foreach ($command_item['examples'] as $example_name => $example_description) {
|
||||
$example_name = str_replace('-', ':', $example_name);
|
||||
$command_annotations[] = "@usage $example_name";
|
||||
$command_annotations[] = " $example_description";
|
||||
}
|
||||
|
|
|
@ -81,11 +81,11 @@ class WebformCommands extends WebformCommandsBase {
|
|||
* @option all Flush all submissions
|
||||
* @option entity-type The entity type for webform submissions to be purged
|
||||
* @option entity-id The ID of the entity for webform submissions to be purged
|
||||
* @usage drush webform-purge
|
||||
* @usage drush webform:purge
|
||||
* Pick a webform and then purge its submissions.
|
||||
* @usage drush webform-purge contact
|
||||
* @usage drush webform:purge contact
|
||||
* Delete 'Contact' webform submissions.
|
||||
* @usage drush webform-purge --all
|
||||
* @usage drush webform:purge ::all
|
||||
* Purge all webform submissions.
|
||||
* @aliases wfp
|
||||
*/
|
||||
|
@ -113,7 +113,7 @@ class WebformCommands extends WebformCommandsBase {
|
|||
* @param $target The module (config/install), config directory (sync), or path (/some/path) that needs its YAML configuration files tidied. (Defaults to webform)
|
||||
* @option dependencies Add module dependencies to installed webform and options configuration entities.
|
||||
* @option prefix Prefix for file names to be tidied. (Defaults to webform)
|
||||
* @usage drush webform-tidy webform
|
||||
* @usage drush webform:tidy webform
|
||||
* Tidies YAML configuration files in 'webform/config' for the Webform module
|
||||
* @aliases wft
|
||||
*/
|
||||
|
@ -129,7 +129,7 @@ class WebformCommands extends WebformCommandsBase {
|
|||
* Displays the status of third party libraries required by the Webform module.
|
||||
*
|
||||
* @command webform:libraries:status
|
||||
* @usage webform-libraries-status
|
||||
* @usage webform:libraries:status
|
||||
* Displays the status of third party libraries required by the Webform module.
|
||||
* @aliases wfls
|
||||
*/
|
||||
|
@ -145,7 +145,7 @@ class WebformCommands extends WebformCommandsBase {
|
|||
* Generates libraries YAML to be included in a drush.make.yml files.
|
||||
*
|
||||
* @command webform:libraries:make
|
||||
* @usage webform-libraries-make
|
||||
* @usage webform:libraries:make
|
||||
* Generates libraries YAML to be included in a drush.make.yml file.
|
||||
* @aliases wflm
|
||||
*/
|
||||
|
@ -162,7 +162,7 @@ class WebformCommands extends WebformCommandsBase {
|
|||
*
|
||||
* @command webform:libraries:composer
|
||||
* @option disable-tls If set to true all HTTPS URLs will be tried with HTTP instead and no network level encryption is performed.
|
||||
* @usage webform-libraries-composer
|
||||
* @usage webform:libraries:composer
|
||||
* Generates the Webform module's composer.json with libraries as repositories.
|
||||
* @aliases wflc
|
||||
*/
|
||||
|
@ -178,7 +178,7 @@ class WebformCommands extends WebformCommandsBase {
|
|||
* Download third party libraries required by the Webform module.
|
||||
*
|
||||
* @command webform:libraries:download
|
||||
* @usage webform-libraries-download
|
||||
* @usage webform:libraries:download
|
||||
* Download third party libraries required by the Webform module.
|
||||
* @aliases wfld
|
||||
*/
|
||||
|
@ -194,7 +194,7 @@ class WebformCommands extends WebformCommandsBase {
|
|||
* Removes all downloaded third party libraries required by the Webform module.
|
||||
*
|
||||
* @command webform:libraries:remove
|
||||
* @usage webform-libraries-remove
|
||||
* @usage webform:libraries:remove
|
||||
* Removes all downloaded third party libraries required by the Webform module.
|
||||
* @aliases wflr
|
||||
*/
|
||||
|
@ -236,11 +236,11 @@ class WebformCommands extends WebformCommandsBase {
|
|||
/****************************************************************************/
|
||||
|
||||
/**
|
||||
* Makes sure all Webform admin settings and webforms are up-to-date.
|
||||
* Makes sure all Webform admin configuration and webform settings are up-to-date.
|
||||
*
|
||||
* @command webform:repair
|
||||
* @usage webform-repair
|
||||
* Repairs admin settings and webforms are up-to-date.
|
||||
* @usage webform:repair
|
||||
* Repairs admin configuration and webform settings are up-to-date.
|
||||
* @aliases wfr
|
||||
*/
|
||||
public function drush_webform_repair() {
|
||||
|
@ -264,7 +264,7 @@ class WebformCommands extends WebformCommandsBase {
|
|||
* Generates HTML documentation.
|
||||
*
|
||||
* @command webform:docs
|
||||
* @usage webform-repair
|
||||
* @usage webform:repair
|
||||
* Generates HTML documentation used by the Webform module's documentation pages.
|
||||
* @aliases wfd
|
||||
*/
|
||||
|
@ -290,7 +290,7 @@ class WebformCommands extends WebformCommandsBase {
|
|||
*
|
||||
* @command webform:composer:update
|
||||
* @option disable-tls If set to true all HTTPS URLs will be tried with HTTP instead and no network level encryption is performed.
|
||||
* @usage webform-composer-update
|
||||
* @usage webform:composer:update
|
||||
* Updates the Drupal installation's composer.json to include the Webform module's selected libraries as repositories.
|
||||
* @aliases wfcu
|
||||
*/
|
||||
|
@ -306,7 +306,7 @@ class WebformCommands extends WebformCommandsBase {
|
|||
* Generate Drush commands from webform.drush.inc for Drush 8.x to WebformCommands for Drush 9.x.
|
||||
*
|
||||
* @command webform:generate:commands
|
||||
* @usage drush webform-generate-commands
|
||||
* @usage drush webform:generate:commands
|
||||
* Generate Drush commands from webform.drush.inc for Drush 8.x to WebformCommands for Drush 9.x.
|
||||
* @aliases wfgc
|
||||
*/
|
||||
|
|
|
@ -0,0 +1,51 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\webform\Controller;
|
||||
|
||||
use Drupal\Core\Controller\ControllerBase;
|
||||
use Drupal\Core\DependencyInjection\ContainerInjectionInterface;
|
||||
use Drupal\webform\WebformHelpManagerInterface;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
|
||||
/**
|
||||
* Provides route responses for webform help.
|
||||
*/
|
||||
class WebformHelpController extends ControllerBase implements ContainerInjectionInterface {
|
||||
|
||||
/**
|
||||
* The webform help manager.
|
||||
*
|
||||
* @var \Drupal\webform\WebformHelpManagerInterface
|
||||
*/
|
||||
protected $help;
|
||||
|
||||
/**
|
||||
* Constructs a WebformHelpController object.
|
||||
*
|
||||
* @param \Drupal\webform\WebformHelpManagerInterface $help
|
||||
* The webform help manager.
|
||||
*/
|
||||
public function __construct(WebformHelpManagerInterface $help) {
|
||||
$this->help = $help;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function create(ContainerInterface $container) {
|
||||
return new static(
|
||||
$container->get('webform.help_manager')
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the Webform extend page.
|
||||
*
|
||||
* @return array
|
||||
* The webform submission webform.
|
||||
*/
|
||||
public function index() {
|
||||
return $this->help->buildIndex();
|
||||
}
|
||||
|
||||
}
|
|
@ -2,80 +2,54 @@
|
|||
|
||||
namespace Drupal\webform\Controller;
|
||||
|
||||
use Drupal\Component\Render\FormattableMarkup;
|
||||
use Drupal\Core\Controller\ControllerBase;
|
||||
use Drupal\webform\Entity\WebformOptions;
|
||||
use Drupal\webform\WebformInterface;
|
||||
use Symfony\Component\HttpFoundation\JsonResponse;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
|
||||
/**
|
||||
* Provides route responses for webform options.
|
||||
* Provides route responses for webform options options.
|
||||
*/
|
||||
class WebformOptionsController extends ControllerBase {
|
||||
|
||||
/**
|
||||
* Returns response for the element autocompletion.
|
||||
* Returns response for the webform options autocompletion.
|
||||
*
|
||||
* @param \Symfony\Component\HttpFoundation\Request $request
|
||||
* The current request object containing the search string.
|
||||
* @param \Drupal\webform\WebformInterface $webform
|
||||
* A webform.
|
||||
* @param string $key
|
||||
* Webform element key.
|
||||
*
|
||||
* @return \Symfony\Component\HttpFoundation\JsonResponse
|
||||
* A JSON response containing the autocomplete suggestions.
|
||||
*/
|
||||
public function autocomplete(Request $request, WebformInterface $webform, $key) {
|
||||
public function autocomplete(Request $request) {
|
||||
$q = $request->query->get('q');
|
||||
|
||||
// Make sure the current user can access this webform.
|
||||
if (!$webform->access('view')) {
|
||||
$webform_options_storage = $this->entityTypeManager()->getStorage('webform_options');
|
||||
|
||||
$query = $webform_options_storage->getQuery()
|
||||
->range(0, 10)
|
||||
->sort('label');
|
||||
|
||||
// Query title and id.
|
||||
$or = $query->orConditionGroup()
|
||||
->condition('id', $q, 'CONTAINS')
|
||||
->condition('label', $q, 'CONTAINS');
|
||||
$query->condition($or);
|
||||
|
||||
$entity_ids = $query->execute();
|
||||
|
||||
if (empty($entity_ids)) {
|
||||
return new JsonResponse([]);
|
||||
}
|
||||
$webform_options = $webform_options_storage->loadMultiple($entity_ids);
|
||||
|
||||
// Get the webform element element.
|
||||
$elements = $webform->getElementsInitializedAndFlattened();
|
||||
if (!isset($elements[$key])) {
|
||||
return new JsonResponse([]);
|
||||
}
|
||||
|
||||
// Get the element's webform options.
|
||||
$element = $elements[$key];
|
||||
$element['#options'] = $element['#autocomplete'];
|
||||
$options = WebformOptions::getElementOptions($element);
|
||||
if (empty($options)) {
|
||||
return new JsonResponse([]);
|
||||
}
|
||||
|
||||
// Filter and convert options to autocomplete matches.
|
||||
$matches = [];
|
||||
$this->appendOptionsToMatchesRecursive($q, $options, $matches);
|
||||
foreach ($webform_options as $webform_option) {
|
||||
$value = new FormattableMarkup('@label (@id)', ['@label' => $webform_option->label(), '@id' => $webform_option->id()]);
|
||||
$matches[] = ['value' => $value, 'label' => $value];
|
||||
}
|
||||
|
||||
return new JsonResponse($matches);
|
||||
}
|
||||
|
||||
/**
|
||||
* Append webform options to autocomplete matches.
|
||||
*
|
||||
* @param string $q
|
||||
* String to filter option's label by.
|
||||
* @param array $options
|
||||
* An associative array of webform options.
|
||||
* @param array $matches
|
||||
* An associative array of autocomplete matches.
|
||||
*/
|
||||
protected function appendOptionsToMatchesRecursive($q, array $options, array &$matches) {
|
||||
foreach ($options as $value => $label) {
|
||||
if (is_array($label)) {
|
||||
$this->appendOptionsToMatchesRecursive($q, $label, $matches);
|
||||
}
|
||||
elseif (stripos($label, $q) !== FALSE) {
|
||||
$matches[] = [
|
||||
'value' => $value,
|
||||
'label' => $label,
|
||||
];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,236 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\webform\Controller;
|
||||
|
||||
use Drupal\Core\Controller\ControllerBase;
|
||||
use Drupal\Core\Database\Connection;
|
||||
use Drupal\Core\Datetime\DateFormatterInterface;
|
||||
use Drupal\Core\Entity\EntityInterface;
|
||||
use Drupal\webform\WebformInterface;
|
||||
use Drupal\webform\WebformRequestInterface;
|
||||
use Drupal\webform\WebformSubmissionInterface;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
|
||||
/**
|
||||
* Returns responses for webform submission log routes.
|
||||
*
|
||||
* Copied from: \Drupal\dblog\Controller\DbLogController.
|
||||
*/
|
||||
class WebformSubmissionLogController extends ControllerBase {
|
||||
|
||||
/**
|
||||
* The database service.
|
||||
*
|
||||
* @var \Drupal\Core\Database\Connection
|
||||
*/
|
||||
protected $database;
|
||||
|
||||
/**
|
||||
* The date formatter service.
|
||||
*
|
||||
* @var \Drupal\Core\Datetime\DateFormatterInterface
|
||||
*/
|
||||
protected $dateFormatter;
|
||||
|
||||
/**
|
||||
* The user storage.
|
||||
*
|
||||
* @var \Drupal\user\UserStorageInterface
|
||||
*/
|
||||
protected $userStorage;
|
||||
|
||||
/**
|
||||
* The webform storage.
|
||||
*
|
||||
* @var \Drupal\webform\WebformStorageInterface
|
||||
*/
|
||||
protected $webformStorage;
|
||||
|
||||
/**
|
||||
* The webform submission storage.
|
||||
*
|
||||
* @var \Drupal\webform\WebformSubmissionStorageInterface
|
||||
*/
|
||||
protected $webformSubmissionStorage;
|
||||
|
||||
/**
|
||||
* Webform request handler.
|
||||
*
|
||||
* @var \Drupal\webform\WebformRequestInterface
|
||||
*/
|
||||
protected $requestHandler;
|
||||
|
||||
/**
|
||||
* Constructs a WebformSubmissionLogController object.
|
||||
*
|
||||
* @param \Drupal\Core\Database\Connection $database
|
||||
* A database connection.
|
||||
* @param \Drupal\Core\Datetime\DateFormatterInterface $date_formatter
|
||||
* The date formatter service.
|
||||
* @param \Drupal\webform\WebformRequestInterface $request_handler
|
||||
* The webform request handler.
|
||||
*/
|
||||
public function __construct(Connection $database, DateFormatterInterface $date_formatter, WebformRequestInterface $request_handler) {
|
||||
$this->database = $database;
|
||||
$this->dateFormatter = $date_formatter;
|
||||
$this->webformStorage = $this->entityTypeManager()->getStorage('webform');
|
||||
$this->webformSubmissionStorage = $this->entityTypeManager()->getStorage('webform_submission');
|
||||
$this->userStorage = $this->entityTypeManager()->getStorage('user');
|
||||
$this->requestHandler = $request_handler;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function create(ContainerInterface $container) {
|
||||
return new static(
|
||||
$container->get('database'),
|
||||
$container->get('date.formatter'),
|
||||
$container->get('webform.request')
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Displays a listing of webform submission log messages.
|
||||
*
|
||||
* @param \Drupal\webform\WebformInterface|null $webform
|
||||
* A webform.
|
||||
* @param \Drupal\webform\WebformSubmissionInterface|null $webform_submission
|
||||
* A webform submission.
|
||||
* @param \Drupal\Core\Entity\EntityInterface|null $source_entity
|
||||
* A source entity.
|
||||
*
|
||||
* @return array
|
||||
* A render array as expected by drupal_render().
|
||||
*/
|
||||
public function overview(WebformInterface $webform = NULL, WebformSubmissionInterface $webform_submission = NULL, EntityInterface $source_entity = NULL) {
|
||||
if (empty($webform) && !empty($webform_submission)) {
|
||||
$webform = $webform_submission->getWebform();
|
||||
}
|
||||
if (empty($source_entity) && !empty($webform_submission)) {
|
||||
$source_entity = $webform_submission->getSourceEntity();
|
||||
}
|
||||
|
||||
// Header.
|
||||
$header = [];
|
||||
$header['lid'] = ['data' => $this->t('#'), 'field' => 'l.lid', 'sort' => 'desc'];
|
||||
if (empty($webform)) {
|
||||
$header['webform_id'] = ['data' => $this->t('Webform'), 'field' => 'l.webform_id', 'class' => [RESPONSIVE_PRIORITY_MEDIUM]];
|
||||
}
|
||||
if (empty($source_entity) && empty($webform_submission)) {
|
||||
$header['entity'] = ['data' => $this->t('Submitted to'), 'class' => [RESPONSIVE_PRIORITY_LOW]];
|
||||
}
|
||||
if (empty($webform_submission)) {
|
||||
$header['sid'] = ['data' => $this->t('Submission'), 'field' => 'l.sid'];
|
||||
}
|
||||
$header['handler_id'] = ['data' => $this->t('Handler'), 'field' => 'l.handler_id'];
|
||||
$header['operation'] = ['data' => $this->t('Operation'), 'field' => 'l.operation', 'class' => [RESPONSIVE_PRIORITY_MEDIUM]];
|
||||
$header['message'] = ['data' => $this->t('Message'), 'field' => 'l.message', 'class' => [RESPONSIVE_PRIORITY_LOW]];
|
||||
$header['uid'] = ['data' => $this->t('User'), 'field' => 'ufd.name', 'class' => [RESPONSIVE_PRIORITY_LOW]];
|
||||
$header['timestamp'] = ['data' => $this->t('Date'), 'field' => 'l.timestamp', 'sort' => 'desc', 'class' => [RESPONSIVE_PRIORITY_LOW]];
|
||||
|
||||
// Query.
|
||||
$query = $this->database->select('webform_submission_log', 'l')
|
||||
->extend('\Drupal\Core\Database\Query\PagerSelectExtender')
|
||||
->extend('\Drupal\Core\Database\Query\TableSortExtender');
|
||||
$query->leftJoin('users_field_data', 'ufd', 'l.uid = ufd.uid');
|
||||
$query->leftJoin('webform_submission', 'ws', 'l.sid = ws.sid');
|
||||
$query->fields('l', [
|
||||
'lid',
|
||||
'uid',
|
||||
'webform_id',
|
||||
'sid',
|
||||
'handler_id',
|
||||
'operation',
|
||||
'message',
|
||||
'timestamp',
|
||||
]);
|
||||
$query->fields('ws', [
|
||||
'entity_type',
|
||||
'entity_id',
|
||||
]);
|
||||
if ($webform) {
|
||||
$query->condition('l.webform_id', $webform->id());
|
||||
}
|
||||
if ($webform_submission) {
|
||||
$query->condition('l.sid', $webform_submission->id());
|
||||
}
|
||||
if ($source_entity) {
|
||||
$query->condition('ws.entity_type', $source_entity->getEntityTypeId());
|
||||
$query->condition('ws.entity_id', $source_entity->id());
|
||||
}
|
||||
$result = $query
|
||||
->limit(50)
|
||||
->orderByHeader($header)
|
||||
->execute();
|
||||
|
||||
// Rows.
|
||||
$rows = [];
|
||||
foreach ($result as $log) {
|
||||
$row = [];
|
||||
$row['lid'] = $log->lid;
|
||||
if (empty($webform)) {
|
||||
$log_webform = $this->webformStorage->load($log->webform_id);
|
||||
$row['webform_id'] = $log_webform->toLink($log_webform->label(), 'results-log');
|
||||
}
|
||||
if (empty($source_entity) && empty($webform_submission)) {
|
||||
$entity = NULL;
|
||||
if ($log->entity_type && $log->entity_id) {
|
||||
$entity_type = $log->entity_type;
|
||||
$entity_id = $log->entity_id;
|
||||
if ($entity = $this->entityTypeManager()->getStorage($entity_type)->load($entity_id)) {
|
||||
$row['entity'] = ($entity->hasLinkTemplate('canonical')) ? $entity->toLink() : "$entity_type:$entity_id";
|
||||
}
|
||||
else {
|
||||
$row['entity'] = "$entity_type:$entity_id";
|
||||
}
|
||||
}
|
||||
else {
|
||||
$row['entity'] = '';
|
||||
}
|
||||
}
|
||||
if (empty($webform_submission)) {
|
||||
if ($log->sid) {
|
||||
$log_webform_submission = $this->webformSubmissionStorage->load($log->sid);
|
||||
$row['sid'] = [
|
||||
'data' => [
|
||||
'#type' => 'link',
|
||||
'#title' => $log->sid,
|
||||
'#url' => $this->requestHandler->getUrl($log_webform_submission, $source_entity, 'webform_submission.log'),
|
||||
],
|
||||
];
|
||||
}
|
||||
else {
|
||||
$row['sid'] = '';
|
||||
}
|
||||
}
|
||||
$row['handler_id'] = $log->handler_id;
|
||||
$row['operation'] = $log->operation;
|
||||
$row['message'] = [
|
||||
'data' => [
|
||||
'#markup' => $log->message,
|
||||
],
|
||||
];
|
||||
$row['uid'] = [
|
||||
'data' => [
|
||||
'#theme' => 'username',
|
||||
'#account' => $this->userStorage->load($log->uid),
|
||||
],
|
||||
];
|
||||
$row['timestamp'] = $this->dateFormatter->format($log->timestamp, 'short');
|
||||
|
||||
$rows[] = $row;
|
||||
}
|
||||
|
||||
$build['table'] = [
|
||||
'#type' => 'table',
|
||||
'#header' => $header,
|
||||
'#rows' => $rows,
|
||||
'#sticky' => TRUE,
|
||||
'#empty' => $this->t('No log messages available.'),
|
||||
];
|
||||
$build['pager'] = ['#type' => 'pager'];
|
||||
return $build;
|
||||
}
|
||||
|
||||
}
|
|
@ -69,6 +69,13 @@ class WebformSubmissionViewController extends EntityViewController {
|
|||
$webform = $this->requestHandler->getCurrentWebform();
|
||||
$source_entity = $this->requestHandler->getCurrentSourceEntity('webform_submission');
|
||||
|
||||
// Set webform submission template.
|
||||
$build = [
|
||||
'#theme' => 'webform_submission',
|
||||
'#view_mode' => $view_mode,
|
||||
'#webform_submission' => $webform_submission,
|
||||
];
|
||||
|
||||
// Navigation.
|
||||
$build['navigation'] = [
|
||||
'#type' => 'webform_submission_navigation',
|
||||
|
|
|
@ -4,17 +4,27 @@ namespace Drupal\webform\Controller;
|
|||
|
||||
use Drupal\Core\Controller\ControllerBase;
|
||||
use Drupal\Core\DependencyInjection\ContainerInjectionInterface;
|
||||
use Drupal\Core\Messenger\MessengerInterface;
|
||||
use Drupal\webform\Plugin\WebformHandler\EmailWebformHandler;
|
||||
use Drupal\webform\WebformInterface;
|
||||
use Drupal\webform\WebformRequestInterface;
|
||||
use Drupal\webform\WebformSubmissionGenerateInterface;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException;
|
||||
|
||||
/**
|
||||
* Provides route responses for webform testing.
|
||||
*/
|
||||
class WebformTestController extends ControllerBase implements ContainerInjectionInterface {
|
||||
|
||||
/**
|
||||
* The messenger.
|
||||
*
|
||||
* @var \Drupal\Core\Messenger\MessengerInterface
|
||||
*/
|
||||
protected $messenger;
|
||||
|
||||
/**
|
||||
* Webform request handler.
|
||||
*
|
||||
|
@ -32,12 +42,15 @@ class WebformTestController extends ControllerBase implements ContainerInjection
|
|||
/**
|
||||
* Constructs a WebformTestController object.
|
||||
*
|
||||
* @param \Drupal\Core\Messenger\MessengerInterface $messenger
|
||||
* The messenger.
|
||||
* @param \Drupal\webform\WebformRequestInterface $request_handler
|
||||
* The webform request handler.
|
||||
* @param \Drupal\webform\WebformSubmissionGenerateInterface $submission_generate
|
||||
* The webform submission generation service.
|
||||
*/
|
||||
public function __construct(WebformRequestInterface $request_handler, WebformSubmissionGenerateInterface $submission_generate) {
|
||||
public function __construct(MessengerInterface $messenger, WebformRequestInterface $request_handler, WebformSubmissionGenerateInterface $submission_generate) {
|
||||
$this->messenger = $messenger;
|
||||
$this->requestHandler = $request_handler;
|
||||
$this->generate = $submission_generate;
|
||||
}
|
||||
|
@ -47,6 +60,7 @@ class WebformTestController extends ControllerBase implements ContainerInjection
|
|||
*/
|
||||
public static function create(ContainerInterface $container) {
|
||||
return new static(
|
||||
$container->get('messenger'),
|
||||
$container->get('webform.request'),
|
||||
$container->get('webform_submission.generate')
|
||||
);
|
||||
|
@ -65,6 +79,45 @@ class WebformTestController extends ControllerBase implements ContainerInjection
|
|||
/** @var \Drupal\webform\WebformInterface $webform */
|
||||
/** @var \Drupal\Core\Entity\EntityInterface $source_entity */
|
||||
list($webform, $source_entity) = $this->requestHandler->getWebformEntities();
|
||||
|
||||
// Test a single webform handler which is set via
|
||||
// ?_webform_handler={handler_id}.
|
||||
$test_webform_handler = $request->query->get('_webform_handler');
|
||||
if ($test_webform_handler) {
|
||||
// Make sure the handler exists.
|
||||
if (!$webform->getHandlers()->has($test_webform_handler)) {
|
||||
$t_args = [
|
||||
'%webform' => $webform->label(),
|
||||
'%handler' => $test_webform_handler,
|
||||
];
|
||||
$this->messenger->addWarning($this->t('The %handler email/handler for the %webform webform does not exist.', $t_args));
|
||||
throw new AccessDeniedHttpException();
|
||||
}
|
||||
|
||||
// Enable only the selected handler for testing
|
||||
// and disable all other handlers.
|
||||
$handlers = $webform->getHandlers();
|
||||
foreach ($handlers as $handler_id => $handler) {
|
||||
if ($handler_id === $test_webform_handler) {
|
||||
$handler->setStatus(TRUE);
|
||||
$t_args = [
|
||||
'%webform' => $webform->label(),
|
||||
'%handler' => $handler->label(),
|
||||
'@type' => ($handler instanceof EmailWebformHandler) ? $this->t('email') : $this->t('handler'),
|
||||
];
|
||||
$this->messenger->addWarning($this->t('Testing the %webform webform %handler @type. <strong>All other emails/handlers are disabled.</strong>', $t_args));
|
||||
}
|
||||
else {
|
||||
$handler->setStatus(FALSE);
|
||||
}
|
||||
}
|
||||
|
||||
// Set override to prevent the webform's altered handler statuses
|
||||
// from being saved.
|
||||
$webform->setOverride(TRUE);
|
||||
}
|
||||
|
||||
// Set values.
|
||||
$values = [];
|
||||
|
||||
// Set source entity type and id.
|
||||
|
|
|
@ -48,6 +48,7 @@ class WebformCodeMirror extends Textarea {
|
|||
'#skip_validation' => FALSE,
|
||||
'#cols' => 60,
|
||||
'#rows' => 5,
|
||||
'#wrap' => TRUE,
|
||||
'#resizable' => 'vertical',
|
||||
'#process' => [
|
||||
[$class, 'processWebformCodeMirror'],
|
||||
|
@ -103,6 +104,11 @@ class WebformCodeMirror extends Textarea {
|
|||
}
|
||||
}
|
||||
|
||||
// Set wrap off.
|
||||
if (empty($element['#wrap'])) {
|
||||
$element['#attributes']['wrap'] = 'off';
|
||||
}
|
||||
|
||||
// Add validate callback.
|
||||
$element += ['#element_validate' => []];
|
||||
array_unshift($element['#element_validate'], [get_called_class(), 'validateWebformCodeMirror']);
|
||||
|
|
|
@ -6,6 +6,7 @@ use Drupal\Component\Utility\NestedArray;
|
|||
use Drupal\Core\EventSubscriber\MainContentViewSubscriber;
|
||||
use Drupal\Core\Form\FormStateInterface;
|
||||
use Drupal\Core\Render\Element\FormElement;
|
||||
use Drupal\Core\Template\Attribute;
|
||||
use Drupal\webform\Entity\WebformSubmission;
|
||||
use Drupal\webform\Utility\WebformHtmlHelper;
|
||||
use Drupal\webform\Utility\WebformXss;
|
||||
|
@ -55,7 +56,7 @@ abstract class WebformComputedBase extends FormElement {
|
|||
[$class, 'processWebformComputed'],
|
||||
],
|
||||
'#input' => TRUE,
|
||||
'#value' => '',
|
||||
'#template' => '',
|
||||
'#mode' => NULL,
|
||||
'#hide_empty' => FALSE,
|
||||
// Note: Computed elements do not use the default #ajax wrapper, which is
|
||||
|
@ -114,7 +115,7 @@ abstract class WebformComputedBase extends FormElement {
|
|||
$wrapper_id = 'webform-computed-' . implode('-', $element['#parents']) . '-wrapper';
|
||||
|
||||
// Get computed value element keys which are used to trigger Ajax updates.
|
||||
preg_match_all('/(?:\[webform_submission:values:|data\.)([_a-z]+)/', $element['#value'], $matches);
|
||||
preg_match_all('/(?:\[webform_submission:values:|data\.)([_a-z]+)/', $element['#template'], $matches);
|
||||
$element_keys = $matches[1] ?: [];
|
||||
$element_keys = array_unique($element_keys);
|
||||
|
||||
|
@ -151,7 +152,7 @@ abstract class WebformComputedBase extends FormElement {
|
|||
'#name' => $button_name,
|
||||
];
|
||||
|
||||
// Attached computed element library.
|
||||
// Attached computed element Ajax library.
|
||||
$element['#attached']['library'][] = 'webform/webform.element.computed';
|
||||
}
|
||||
|
||||
|
@ -170,7 +171,7 @@ abstract class WebformComputedBase extends FormElement {
|
|||
* The string with tokens replaced.
|
||||
*/
|
||||
public static function processValue(array $element, WebformSubmissionInterface $webform_submission) {
|
||||
return $element['#value'];
|
||||
return $element['#template'];
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -204,11 +205,15 @@ abstract class WebformComputedBase extends FormElement {
|
|||
protected static function setWebformComputedElementValue(array &$element, $value) {
|
||||
// Hide empty computed element using display:none so that #states API
|
||||
// can still use the empty computed value.
|
||||
if ($value === '' && $element['#hide_empty']) {
|
||||
$element['#wrapper_attributes']['style'] = 'display:none';
|
||||
}
|
||||
else {
|
||||
unset($element['#wrapper_attributes']);
|
||||
if ($element['#hide_empty']) {
|
||||
$element += ['#wrapper_attributes' => []];
|
||||
$element['#wrapper_attributes'] += ['style' => ''];
|
||||
if ($value === '') {
|
||||
$element['#wrapper_attributes']['style'] .= ($element['#wrapper_attributes']['style'] ? ';' : '') . 'display:none';
|
||||
}
|
||||
else {
|
||||
$element['#wrapper_attributes']['style'] = preg_replace('/;?display:none/', '', $element['#wrapper_attributes']['style']);
|
||||
}
|
||||
}
|
||||
|
||||
// Display markup.
|
||||
|
@ -279,7 +284,18 @@ abstract class WebformComputedBase extends FormElement {
|
|||
// Only return the wrapper id, this prevents the computed element from
|
||||
// being reinitialized via JS after each update.
|
||||
// @see js/webform.element.computed.js
|
||||
$element['#prefix'] = '<div class="js-webform-computed-wrapper" id="' . $element['#wrapper_id'] . '">';
|
||||
//
|
||||
// The announce attribute allows FAPI Ajax callbacks to easily
|
||||
// trigger announcements.
|
||||
// @see js/webform.announce.js
|
||||
$t_args = ['@title' => $element['#title'], '@value' => strip_tags($value)];
|
||||
$attributes = [
|
||||
'class' => ['js-webform-computed-wrapper'],
|
||||
'id' => $element['#wrapper_id'],
|
||||
'data-webform-announce' => t('@title is @value', $t_args),
|
||||
];
|
||||
$element['#prefix'] = '<div' . new Attribute($attributes) . '>';
|
||||
|
||||
$element['#suffix'] = '</div>';
|
||||
|
||||
// Remove flexbox wrapper because it already been render outside this
|
||||
|
@ -311,7 +327,7 @@ abstract class WebformComputedBase extends FormElement {
|
|||
*/
|
||||
public static function getMode(array $element) {
|
||||
if (empty($element['#mode']) || $element['#mode'] === static::MODE_AUTO) {
|
||||
return (WebformHtmlHelper::containsHtml($element['#value'])) ? static::MODE_HTML : static::MODE_TEXT;
|
||||
return (WebformHtmlHelper::containsHtml($element['#template'])) ? static::MODE_HTML : static::MODE_TEXT;
|
||||
}
|
||||
else {
|
||||
return $element['#mode'];
|
||||
|
|
|
@ -21,7 +21,7 @@ class WebformComputedToken extends WebformComputedBase {
|
|||
$token_manager = \Drupal::service('webform.token_manager');
|
||||
|
||||
// Replace tokens in value.
|
||||
return $token_manager->replace($element['#value'], $webform_submission, [], ['html' => ($mode == static::MODE_HTML)]);
|
||||
return $token_manager->replace($element['#template'], $webform_submission, [], ['html' => ($mode == static::MODE_HTML)]);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -41,7 +41,7 @@ class WebformComputedTwig extends WebformComputedBase {
|
|||
public static function processValue(array $element, WebformSubmissionInterface $webform_submission) {
|
||||
$whitespace = (!empty($element['#whitespace'])) ? $element['#whitespace'] : '';
|
||||
|
||||
$template = ($whitespace === static::WHITESPACE_SPACELESS) ? '{% spaceless %}' . $element['#value'] . '{% endspaceless %}' : $element['#value'];
|
||||
$template = ($whitespace === static::WHITESPACE_SPACELESS) ? '{% spaceless %}' . $element['#template'] . '{% endspaceless %}' : $element['#template'];
|
||||
|
||||
$options = ['html' => (static::getMode($element) === static::MODE_HTML)];
|
||||
|
||||
|
|
|
@ -27,6 +27,7 @@ class WebformElementStates extends FormElement {
|
|||
return [
|
||||
'#input' => TRUE,
|
||||
'#selector_options' => [],
|
||||
'#selector_sources' => [],
|
||||
'#empty_states' => 3,
|
||||
'#process' => [
|
||||
[$class, 'processWebformStates'],
|
||||
|
@ -66,6 +67,7 @@ class WebformElementStates extends FormElement {
|
|||
* Expand an email confirm field into two HTML5 email elements.
|
||||
*/
|
||||
public static function processWebformStates(&$element, FormStateInterface $form_state, &$complete_form) {
|
||||
|
||||
// Define default #state_options and #trigger_options.
|
||||
// There are also defined by \Drupal\webform\Plugin\WebformElementBase::form.
|
||||
$element += [
|
||||
|
@ -75,18 +77,33 @@ class WebformElementStates extends FormElement {
|
|||
|
||||
$element['#tree'] = TRUE;
|
||||
|
||||
$edit_source = $form_state->get(static::getStorageKey($element, 'edit_source'));
|
||||
|
||||
// Add validate callback that extracts the associative array of states.
|
||||
$element += ['#element_validate' => []];
|
||||
array_unshift($element['#element_validate'], [get_called_class(), 'validateWebformElementStates']);
|
||||
|
||||
// For customized #states display a CodeMirror YAML editor.
|
||||
if ($warning_message = static::isDefaultValueCustomizedFormApiStates($element)) {
|
||||
$warning_message .= ' ' . t('Form API #states must be manually entered.');
|
||||
$element['messages'] = [
|
||||
'#type' => 'webform_message',
|
||||
'#message_type' => 'warning',
|
||||
'#message_message' => $warning_message,
|
||||
];
|
||||
$warning_message = static::isDefaultValueCustomizedFormApiStates($element);
|
||||
if ($warning_message || $edit_source) {
|
||||
if ($warning_message) {
|
||||
$warning_message .= ' ' . t('Form API #states must be manually entered.');
|
||||
$element['warning_messages'] = [
|
||||
'#type' => 'webform_message',
|
||||
'#message_type' => 'warning',
|
||||
'#message_message' => $warning_message,
|
||||
];
|
||||
}
|
||||
|
||||
if ($edit_source) {
|
||||
$element['edit_source_message'] = [
|
||||
'#type' => 'webform_message',
|
||||
'#message_message' => t('Creating custom conditional logic (Form API #states) with nested conditions or custom selectors will disable the conditional logic builder. This will require that Form API #states be manually entered.'),
|
||||
'#message_type' => 'info',
|
||||
'#message_close' => TRUE,
|
||||
'#message_storage' => WebformMessage::STORAGE_SESSION,
|
||||
];
|
||||
}
|
||||
$element['states'] = [
|
||||
'#type' => 'webform_codemirror',
|
||||
'#title' => t('Conditional Logic (YAML)'),
|
||||
|
@ -94,6 +111,9 @@ class WebformElementStates extends FormElement {
|
|||
'#mode' => 'yaml',
|
||||
'#default_value' => WebformYaml::encode($element['#default_value']),
|
||||
'#description' => t('Learn more about Drupal\'s <a href=":href">Form API #states</a>.', [':href' => 'https://www.lullabot.com/articles/form-api-states']),
|
||||
'#webform_element' => TRUE,
|
||||
'#more_title' => t('Help'),
|
||||
'#more' => static::buildSourceHelp($element),
|
||||
];
|
||||
return $element;
|
||||
}
|
||||
|
@ -164,17 +184,22 @@ class WebformElementStates extends FormElement {
|
|||
}
|
||||
}
|
||||
|
||||
// Add wrapper to the element.
|
||||
$element += ['#prefix' => '', '#suffix' => ''];
|
||||
$element['#prefix'] = '<div id="' . $table_id . '">' . $element['#prefix'];
|
||||
$element['#suffix'] .= '</div>';
|
||||
|
||||
// Build table.
|
||||
$element['states'] = [
|
||||
'#prefix' => '<div id="' . $table_id . '" class="webform-states-table">',
|
||||
'#suffix' => '</div>',
|
||||
'#type' => 'table',
|
||||
'#header' => $header,
|
||||
'#attributes' => ['class' => ['webform-states-table']],
|
||||
] + $rows;
|
||||
|
||||
$element['actions'] = ['#type' => 'container'];
|
||||
// Build add state action.
|
||||
if ($element['#multiple']) {
|
||||
$element['add'] = [
|
||||
$element['actions']['add'] = [
|
||||
'#type' => 'submit',
|
||||
'#value' => t('Add another state'),
|
||||
'#limit_validation_errors' => [],
|
||||
|
@ -184,6 +209,19 @@ class WebformElementStates extends FormElement {
|
|||
];
|
||||
}
|
||||
|
||||
// Edit source.
|
||||
if (\Drupal::currentUser()->hasPermission('edit webform source')) {
|
||||
$element['actions']['source'] = [
|
||||
'#type' => 'submit',
|
||||
'#value' => t('Edit source'),
|
||||
'#limit_validation_errors' => [],
|
||||
'#submit' => [[get_called_class(), 'editSourceSubmit']],
|
||||
'#ajax' => $ajax_settings,
|
||||
'#attributes' => ['class' => ['button', 'button--danger']],
|
||||
'#name' => $table_id . '_source',
|
||||
];
|
||||
}
|
||||
|
||||
// Display a warning message when a state is set to disabled or enabled.
|
||||
$total_state_row_indexes = count($state_row_indexes);
|
||||
$triggers = [];
|
||||
|
@ -197,7 +235,7 @@ class WebformElementStates extends FormElement {
|
|||
if (!empty($element['#disabled_message'])) {
|
||||
$element['disabled_message'] = [
|
||||
'#type' => 'webform_message',
|
||||
'#message_message' => t('<a href="https://www.w3schools.com/tags/att_input_disabled.asp" target="_blank">Disabled</a> elements do not submit data back to the server and the element\'s server-side default or current value will be preserved and saved to the database.'),
|
||||
'#message_message' => t('<a href="https://www.w3schools.com/tags/att_input_disabled.asp">Disabled</a> elements do not submit data back to the server and the element\'s server-side default or current value will be preserved and saved to the database.'),
|
||||
'#message_type' => 'warning',
|
||||
'#states' => ['visible' => $triggers],
|
||||
];
|
||||
|
@ -205,9 +243,109 @@ class WebformElementStates extends FormElement {
|
|||
|
||||
$element['#attached']['library'][] = 'webform/webform.element.states';
|
||||
|
||||
// Convert #options to jQuery autocomplete source format.
|
||||
// @see http://api.jqueryui.com/autocomplete/#option-source
|
||||
$selectors = [];
|
||||
$sources = [];
|
||||
if ($element['#selector_sources']) {
|
||||
foreach ($element['#selector_sources'] as $selector => $values) {
|
||||
$sources_key = md5(serialize($values));
|
||||
$selectors[$selector] = $sources_key;
|
||||
if (!isset($sources[$sources_key])) {
|
||||
foreach ($values as $key => $value) {
|
||||
$sources[$sources_key][] = [
|
||||
'label' => (string) $value . ($value != $key ? ' (' . $key . ')' : ''),
|
||||
'value' => (string) $key,
|
||||
];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
$element['#attached']['drupalSettings']['webformElementStates'] = [
|
||||
'selectors' => $selectors,
|
||||
'sources' => $sources,
|
||||
];
|
||||
|
||||
return $element;
|
||||
}
|
||||
|
||||
/**
|
||||
* Build edit source help.
|
||||
*
|
||||
* @param array $element
|
||||
* An element.
|
||||
*
|
||||
* @return array
|
||||
* A renderable array.
|
||||
*/
|
||||
protected static function buildSourceHelp(array $element) {
|
||||
$build = [];
|
||||
$build['states'] = [
|
||||
'title' => [
|
||||
'#markup' => t('Available states'),
|
||||
'#prefix' => '<strong>',
|
||||
'#suffix' => '</strong>',
|
||||
],
|
||||
'items' => static::convertOptionToItemList($element['#state_options']),
|
||||
];
|
||||
if ($element['#selector_options']) {
|
||||
$build['selectors'] = [
|
||||
'title' => [
|
||||
'#markup' => t('Available selectors'),
|
||||
'#prefix' => '<strong>',
|
||||
'#suffix' => '</strong>',
|
||||
],
|
||||
'items' => static::convertOptionToItemList($element['#selector_options']),
|
||||
];
|
||||
}
|
||||
$build['triggers'] = [
|
||||
'title' => [
|
||||
'#markup' => t('Available triggers'),
|
||||
'#prefix' => '<strong>',
|
||||
'#suffix' => '</strong>',
|
||||
],
|
||||
'items' => static::convertOptionToItemList($element['#trigger_options']),
|
||||
];
|
||||
return $build;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert options with optgroup to item list.
|
||||
*
|
||||
* @param array $options
|
||||
* An array of options.
|
||||
*
|
||||
* @return array
|
||||
* A renderable array.
|
||||
*/
|
||||
protected static function convertOptionToItemList(array $options) {
|
||||
$items = [];
|
||||
foreach ($options as $option_name => $option_value) {
|
||||
if (is_array($option_value)) {
|
||||
$items[$option_name] = [
|
||||
'title' => [
|
||||
'#markup' => $option_name,
|
||||
],
|
||||
'children' => [
|
||||
'#theme' => 'item_list',
|
||||
'#items' => array_keys($option_value),
|
||||
],
|
||||
];
|
||||
}
|
||||
else {
|
||||
$items[$option_name] = [
|
||||
'#markup' => $option_name,
|
||||
'#prefix' => '<div>',
|
||||
'#suffix' => '</div>',
|
||||
];
|
||||
}
|
||||
}
|
||||
return [
|
||||
'#theme' => 'item_list',
|
||||
'#items' => $items,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Build state row.
|
||||
*
|
||||
|
@ -240,6 +378,7 @@ class WebformElementStates extends FormElement {
|
|||
'#default_value' => $state['state'],
|
||||
'#empty_option' => t('- Select -'),
|
||||
'#wrapper_attributes' => ['class' => ['webform-states-table--state']],
|
||||
'#error_no_message' => TRUE,
|
||||
];
|
||||
$row['operator'] = [
|
||||
'#type' => 'select',
|
||||
|
@ -254,6 +393,7 @@ class WebformElementStates extends FormElement {
|
|||
'#field_prefix' => t('if'),
|
||||
'#field_suffix' => t('of the following is met:'),
|
||||
'#wrapper_attributes' => ['class' => ['webform-states-table--operator'], 'colspan' => 2, 'align' => 'left'],
|
||||
'#error_no_message' => TRUE,
|
||||
];
|
||||
$row['operations'] = static::buildOperations($table_id, $row_index, $ajax_settings);
|
||||
if (!$element['#multiple']) {
|
||||
|
@ -299,6 +439,7 @@ class WebformElementStates extends FormElement {
|
|||
'#wrapper_attributes' => ['class' => ['webform-states-table--selector']],
|
||||
'#default_value' => $condition['selector'],
|
||||
'#empty_option' => t('- Select -'),
|
||||
'#error_no_message' => TRUE,
|
||||
];
|
||||
if (!isset($element['#selector_options'][$condition['selector']])) {
|
||||
$row['selector']['#options'][$condition['selector']] = $condition['selector'];
|
||||
|
@ -315,6 +456,7 @@ class WebformElementStates extends FormElement {
|
|||
'#empty_option' => t('- Select -'),
|
||||
'#parents' => [$element_name, 'states', $row_index , 'trigger'],
|
||||
'#wrapper_attributes' => ['class' => ['webform-states-table--trigger']],
|
||||
'#error_no_message' => TRUE,
|
||||
];
|
||||
$row['condition']['value'] = [
|
||||
'#type' => 'textfield',
|
||||
|
@ -340,6 +482,7 @@ class WebformElementStates extends FormElement {
|
|||
],
|
||||
'#wrapper_attributes' => ['class' => ['webform-states-table--value']],
|
||||
'#parents' => [$element_name, 'states', $row_index , 'value'],
|
||||
'#error_no_message' => TRUE,
|
||||
];
|
||||
$row['condition']['pattern'] = [
|
||||
'#type' => 'container',
|
||||
|
@ -402,7 +545,7 @@ class WebformElementStates extends FormElement {
|
|||
/****************************************************************************/
|
||||
|
||||
/**
|
||||
* Webform submission handler for adding another state.
|
||||
* Form submission handler for adding another state.
|
||||
*
|
||||
* @param array $form
|
||||
* An associative array containing the structure of the form.
|
||||
|
@ -412,7 +555,7 @@ class WebformElementStates extends FormElement {
|
|||
public static function addStateSubmit(array &$form, FormStateInterface $form_state) {
|
||||
// Get the webform states element by going up one level.
|
||||
$button = $form_state->getTriggeringElement();
|
||||
$element =& NestedArray::getValue($form, array_slice($button['#array_parents'], 0, -1));
|
||||
$element =& NestedArray::getValue($form, array_slice($button['#array_parents'], 0, -2));
|
||||
|
||||
$values = $element['states']['#value'];
|
||||
|
||||
|
@ -434,12 +577,12 @@ class WebformElementStates extends FormElement {
|
|||
// Update the number of rows.
|
||||
$form_state->set(static::getStorageKey($element, 'number_of_rows'), count($values));
|
||||
|
||||
// Rebuild the webform.
|
||||
// Rebuild the form.
|
||||
$form_state->setRebuild();
|
||||
}
|
||||
|
||||
/**
|
||||
* Webform submission handler for adding another condition.
|
||||
* Form submission handler for adding another condition.
|
||||
*
|
||||
* @param array $form
|
||||
* An associative array containing the structure of the form.
|
||||
|
@ -472,12 +615,12 @@ class WebformElementStates extends FormElement {
|
|||
// Update the number of rows.
|
||||
$form_state->set(static::getStorageKey($element, 'number_of_rows'), count($values));
|
||||
|
||||
// Rebuild the webform.
|
||||
// Rebuild the form.
|
||||
$form_state->setRebuild();
|
||||
}
|
||||
|
||||
/**
|
||||
* Webform submission handler for removing a state or condition.
|
||||
* Form submission handler for removing a state or condition.
|
||||
*
|
||||
* @param array $form
|
||||
* An associative array containing the structure of the form.
|
||||
|
@ -513,7 +656,32 @@ class WebformElementStates extends FormElement {
|
|||
// Update the number of rows.
|
||||
$form_state->set(static::getStorageKey($element, 'number_of_rows'), count($values));
|
||||
|
||||
// Rebuild the webform.
|
||||
// Rebuild the form.
|
||||
$form_state->setRebuild();
|
||||
}
|
||||
|
||||
/**
|
||||
* Form submission handler for editing source.
|
||||
*
|
||||
* @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.
|
||||
*/
|
||||
public static function editSourceSubmit(array &$form, FormStateInterface $form_state) {
|
||||
// Get the webform states element by going up one level.
|
||||
$button = $form_state->getTriggeringElement();
|
||||
$element =& NestedArray::getValue($form, array_slice($button['#array_parents'], 0, -2));
|
||||
|
||||
// Set edit source.
|
||||
$form_state->set(static::getStorageKey($element, 'edit_source'), TRUE);
|
||||
|
||||
// Convert states to editable string.
|
||||
$value = $element['#value'] ? Yaml::encode($element['#value']) : '';
|
||||
$form_state->setValueForElement($element['states'], $value);
|
||||
NestedArray::setValue($form_state->getUserInput(), $element['states']['#parents'], $value);
|
||||
|
||||
// Rebuild the form.
|
||||
$form_state->setRebuild();
|
||||
}
|
||||
|
||||
|
@ -522,9 +690,9 @@ class WebformElementStates extends FormElement {
|
|||
*/
|
||||
public static function ajaxCallback(array &$form, FormStateInterface $form_state) {
|
||||
$button = $form_state->getTriggeringElement();
|
||||
$parent_length = (isset($button['#row_index'])) ? -4 : -1;
|
||||
$parent_length = (isset($button['#row_index'])) ? -4 : -2;
|
||||
$element = NestedArray::getValue($form, array_slice($button['#array_parents'], 0, $parent_length));
|
||||
return $element['states'];
|
||||
return $element;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -535,7 +703,11 @@ class WebformElementStates extends FormElement {
|
|||
$states = Yaml::decode($element['states']['#value']);
|
||||
}
|
||||
else {
|
||||
$states = static::convertFormValuesToFormApiStates($element['states']['#value']);
|
||||
$errors = [];
|
||||
$states = static::convertElementValueToFormApiStates($element, $errors);
|
||||
if ($errors) {
|
||||
$form_state->setError($element, reset($errors));
|
||||
}
|
||||
}
|
||||
$form_state->setValueForElement($element, NULL);
|
||||
|
||||
|
@ -624,22 +796,30 @@ class WebformElementStates extends FormElement {
|
|||
}
|
||||
|
||||
/**
|
||||
* Convert states array to Form API #states.
|
||||
* Convert an element's submitted value to Form API #states.
|
||||
*
|
||||
* @param array $states_array
|
||||
* An associative array containing states.
|
||||
* @param array $element
|
||||
* The form element.
|
||||
* @param array $errors
|
||||
* An array used to capture errors.
|
||||
*
|
||||
* @return array
|
||||
* An associative array of states.
|
||||
*/
|
||||
protected static function convertStatesArrayToFormApiStates(array $states_array = []) {
|
||||
protected static function convertElementValueToFormApiStates(array $element, array &$errors = []) {
|
||||
$states = [];
|
||||
$states_array = static::convertFormValuesToStatesArray($element['states']['#value']);
|
||||
foreach ($states_array as $state_array) {
|
||||
$state = $state_array['state'];
|
||||
if (!$state) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Check for duplicate states.
|
||||
if (isset($states[$state])) {
|
||||
static::setFormApiStateError($element, $errors, $state);
|
||||
}
|
||||
|
||||
// Define values extracted from
|
||||
// WebformElementStates::getFormApiStatesCondition().
|
||||
$selector = NULL;
|
||||
|
@ -651,6 +831,10 @@ class WebformElementStates extends FormElement {
|
|||
if (count($conditions) === 1) {
|
||||
$condition = reset($conditions);
|
||||
extract(static::getFormApiStatesCondition($condition));
|
||||
// Check for duplicate selectors.
|
||||
if (isset($states[$state][$selector])) {
|
||||
static::setFormApiStateError($element, $errors, $state, $selector);
|
||||
}
|
||||
$states[$state][$selector][$trigger] = $value;
|
||||
}
|
||||
else {
|
||||
|
@ -668,6 +852,10 @@ class WebformElementStates extends FormElement {
|
|||
];
|
||||
}
|
||||
else {
|
||||
// Check for duplicate selectors.
|
||||
if (isset($states[$state][$selector])) {
|
||||
static::setFormApiStateError($element, $errors, $state, $selector);
|
||||
}
|
||||
$states[$state][$selector] = [
|
||||
$trigger => $value,
|
||||
];
|
||||
|
@ -679,6 +867,37 @@ class WebformElementStates extends FormElement {
|
|||
return $states;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set Form API state error.
|
||||
*
|
||||
* @param array $element
|
||||
* The form element.
|
||||
* @param array $errors
|
||||
* An array used to capture errors.
|
||||
* @param null|string $state
|
||||
* An element state.
|
||||
* @param null|string $selector
|
||||
* An element selector.
|
||||
*/
|
||||
protected static function setFormApiStateError(array $element, array &$errors, $state = NULL, $selector = NULL) {
|
||||
$state_options = OptGroup::flattenOptions($element['#state_options']);
|
||||
$selector_options = OptGroup::flattenOptions($element['#selector_options']);
|
||||
|
||||
if ($state && !$selector) {
|
||||
$t_args = [
|
||||
'%state' => $state_options[$state],
|
||||
];
|
||||
$errors[] = t('The %state state is declared more than once. There can only be one declaration per state.', $t_args);
|
||||
}
|
||||
elseif ($state && $selector) {
|
||||
$t_args = [
|
||||
'%selector' => $selector_options[$selector],
|
||||
'%state' => $state_options[$state],
|
||||
];
|
||||
$errors[] = t('The %selector element is used more than once within the %state state. To use multiple values within a trigger try using the pattern trigger.', $t_args);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get FAPI states array condition.
|
||||
*
|
||||
|
@ -722,7 +941,7 @@ class WebformElementStates extends FormElement {
|
|||
* @return array
|
||||
* An associative array of states.
|
||||
*/
|
||||
public static function convertFormValuesToStatesArray(array $values = []) {
|
||||
protected static function convertFormValuesToStatesArray(array $values = []) {
|
||||
$index = 0;
|
||||
|
||||
$states = [];
|
||||
|
@ -742,20 +961,6 @@ class WebformElementStates extends FormElement {
|
|||
return $states;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert webform values to states array.
|
||||
*
|
||||
* @param array $values
|
||||
* Submitted webform values to converted to states array.
|
||||
*
|
||||
* @return array
|
||||
* An associative array of states.
|
||||
*/
|
||||
public static function convertFormValuesToFormApiStates(array $values = []) {
|
||||
$values = static::convertFormValuesToStatesArray($values);
|
||||
return static::convertStatesArrayToFormApiStates($values);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if an element's #states array is customized.
|
||||
*
|
||||
|
@ -765,7 +970,7 @@ class WebformElementStates extends FormElement {
|
|||
* @return bool|string
|
||||
* FALSE if #states array is not customized or a warning message.
|
||||
*/
|
||||
public static function isDefaultValueCustomizedFormApiStates(array $element) {
|
||||
protected static function isDefaultValueCustomizedFormApiStates(array $element) {
|
||||
// Empty default values are not customized.
|
||||
if (empty($element['#default_value'])) {
|
||||
return FALSE;
|
||||
|
|
|
@ -26,13 +26,15 @@ trait WebformEntityTrait {
|
|||
*
|
||||
* @param array $element
|
||||
* An element.
|
||||
* @param array $settings
|
||||
* An array of settings used to limit and randomize options.
|
||||
*
|
||||
* @throws \Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException
|
||||
* Thrown when the current user doesn't have access to the specified entity.
|
||||
*
|
||||
* @see \Drupal\system\Controller\EntityAutocompleteController
|
||||
*/
|
||||
public static function setOptions(array &$element) {
|
||||
public static function setOptions(array &$element, $settings = []) {
|
||||
if (!empty($element['#options'])) {
|
||||
return;
|
||||
}
|
||||
|
@ -41,6 +43,9 @@ trait WebformEntityTrait {
|
|||
'target_type' => $element['#target_type'],
|
||||
'handler' => $element['#selection_handler'],
|
||||
'handler_settings' => (isset($element['#selection_settings'])) ? $element['#selection_settings'] : [],
|
||||
// Set '_webform_settings' used to limit and randomize options.
|
||||
// @see webform_query_entity_reference_alter()
|
||||
'_webform_settings' => $settings,
|
||||
];
|
||||
|
||||
/** @var \Drupal\Core\Entity\EntityReferenceSelection\SelectionPluginManagerInterface $selection_manager */
|
||||
|
|
|
@ -60,6 +60,7 @@ class WebformMapping extends FormElement {
|
|||
$destination_element_base = [
|
||||
'#title_display' => 'invisible',
|
||||
'#required' => ($element['#required'] === self::REQUIRED_ALL) ? TRUE : FALSE,
|
||||
'#error_no_message' => ($element['#required'] !== self::REQUIRED_ALL) ? TRUE : FALSE,
|
||||
];
|
||||
|
||||
// Get base #destination__* properties.
|
||||
|
|
|
@ -152,10 +152,9 @@ class WebformMultiple extends FormElement {
|
|||
}
|
||||
|
||||
// Add wrapper to the element.
|
||||
$element += [
|
||||
'#prefix' => '<div id="' . $table_id . '">',
|
||||
'#suffix' => '</div>',
|
||||
];
|
||||
$element += ['#prefix' => '', '#suffix' => ''];
|
||||
$element['#prefix'] = '<div id="' . $table_id . '">' . $element['#prefix'];
|
||||
$element['#suffix'] .= '</div>';
|
||||
|
||||
// DEBUG:
|
||||
// Disable Ajax callback by commenting out the below callback and wrapper.
|
||||
|
@ -774,7 +773,7 @@ class WebformMultiple extends FormElement {
|
|||
$action_key = static::getStorageKey($element, 'action');
|
||||
$form_state->set($action_key, TRUE);
|
||||
|
||||
// Rebuild the webform.
|
||||
// Rebuild the form.
|
||||
$form_state->setRebuild();
|
||||
}
|
||||
|
||||
|
@ -811,7 +810,7 @@ class WebformMultiple extends FormElement {
|
|||
$action_key = static::getStorageKey($element, 'action');
|
||||
$form_state->set($action_key, TRUE);
|
||||
|
||||
// Rebuild the webform.
|
||||
// Rebuild the form.
|
||||
$form_state->setRebuild();
|
||||
}
|
||||
|
||||
|
@ -847,7 +846,7 @@ class WebformMultiple extends FormElement {
|
|||
$action_key = static::getStorageKey($element, 'action');
|
||||
$form_state->set($action_key, TRUE);
|
||||
|
||||
// Rebuild the webform.
|
||||
// Rebuild the form.
|
||||
$form_state->setRebuild();
|
||||
}
|
||||
|
||||
|
|
|
@ -115,6 +115,7 @@ abstract class WebformOtherBase extends FormElement {
|
|||
$element[$type]['#pre_render'] = [];
|
||||
|
||||
// Build other textfield.
|
||||
$element += ['other' => []];
|
||||
foreach ($element as $key => $value) {
|
||||
if (strpos($key, '#other__') === 0) {
|
||||
$other_key = str_replace('#other__', '#', $key);
|
||||
|
|
|
@ -12,7 +12,7 @@ use Drupal\Core\Form\FormStateInterface;
|
|||
*
|
||||
* @code
|
||||
* $form['time'] = array(
|
||||
* '#type' => 'time',
|
||||
* '#type' => 'webform_time',
|
||||
* '#title' => $this->t('Time'),
|
||||
* '#default_value' => '12:00 AM'
|
||||
* );
|
||||
|
@ -48,7 +48,7 @@ class WebformTime extends FormElement {
|
|||
// Set default value using GNU PHP date format.
|
||||
// @see https://www.gnu.org/software/tar/manual/html_chapter/tar_7.html#Date-input-formats.
|
||||
if (!empty($element['#default_value'])) {
|
||||
$element['#default_value'] = date('H:i', strtotime($element['#default_value']));
|
||||
$element['#default_value'] = static::formatTime('H:i', strtotime($element['#default_value']));
|
||||
return $element['#default_value'];
|
||||
}
|
||||
}
|
||||
|
@ -83,7 +83,7 @@ class WebformTime extends FormElement {
|
|||
/**
|
||||
* Webform element validation handler for #type 'webform_time'.
|
||||
*
|
||||
* Note that #required is validated by _form_validate() already.
|
||||
* Note that #required is validated by _form_valistatic::formatTime() already.
|
||||
*/
|
||||
public static function validateWebformTime(&$element, FormStateInterface $form_state, &$complete_form) {
|
||||
$has_access = (!isset($element['#access']) || $element['#access'] === TRUE);
|
||||
|
@ -115,7 +115,7 @@ class WebformTime extends FormElement {
|
|||
if ($time < $min) {
|
||||
$form_state->setError($element, t('%name must be on or after %min.', [
|
||||
'%name' => $name,
|
||||
'%min' => date($time_format, $min),
|
||||
'%min' => static::formatTime($time_format, $min),
|
||||
]));
|
||||
}
|
||||
}
|
||||
|
@ -126,12 +126,12 @@ class WebformTime extends FormElement {
|
|||
if ($time > $max) {
|
||||
$form_state->setError($element, t('%name must be on or before %max.', [
|
||||
'%name' => $name,
|
||||
'%max' => date($time_format, $max),
|
||||
'%max' => static::formatTime($time_format, $max),
|
||||
]));
|
||||
}
|
||||
}
|
||||
|
||||
$value = date('H:i:s', $time);
|
||||
$value = static::formatTime('H:i:s', $time);
|
||||
$element['#value'] = $value;
|
||||
$form_state->setValueForElement($element, $value);
|
||||
}
|
||||
|
@ -151,15 +151,33 @@ class WebformTime extends FormElement {
|
|||
$element['#attributes']['type'] = 'text';
|
||||
// Apply #time_format to #value.
|
||||
if (!empty($element['#value'])) {
|
||||
$element['#value'] = date($element['#attributes']['data-webform-time-format'], strtotime($element['#value']));
|
||||
$element['#value'] = static::formatTime($element['#attributes']['data-webform-time-format'], strtotime($element['#value']));
|
||||
}
|
||||
}
|
||||
else {
|
||||
$element['#attributes']['type'] = 'time';
|
||||
}
|
||||
Element::setAttributes($element, ['id', 'name', 'type', 'value', 'size', 'min', 'max', 'step']);
|
||||
Element::setAttributes($element, ['id', 'name', 'type', 'value', 'size', 'maxlength', 'min', 'max', 'step']);
|
||||
static::setAttributes($element, ['form-time', 'webform-time']);
|
||||
return $element;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Format custom time.
|
||||
*
|
||||
* @param string $custom_format
|
||||
* A PHP date format string suitable for input to date().
|
||||
* @param int $timestamp
|
||||
* (optional) A UNIX timestamp to format.
|
||||
*
|
||||
* @return string
|
||||
* Formatted time.
|
||||
*/
|
||||
protected static function formatTime($custom_format, $timestamp = NULL) {
|
||||
/** @var \Drupal\Core\Datetime\DateFormatterInterface $date_formatter */
|
||||
$date_formatter = \Drupal::service('date.formatter');
|
||||
return $date_formatter->format($timestamp ?: time(), 'custom', $custom_format);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -126,6 +126,13 @@ class Webform extends ConfigEntityBundleBase implements WebformInterface {
|
|||
*/
|
||||
protected $uuid;
|
||||
|
||||
/**
|
||||
* The webform's current operation.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $operation;
|
||||
|
||||
/**
|
||||
* The webform override state.
|
||||
*
|
||||
|
@ -436,6 +443,29 @@ class Webform extends ConfigEntityBundleBase implements WebformInterface {
|
|||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getOperation() {
|
||||
return $this->operation;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function setOperation($operation) {
|
||||
$this->operation = $operation;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function isTest() {
|
||||
return ($this->operation === 'test') ? TRUE : FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
|
@ -557,6 +587,13 @@ class Webform extends ConfigEntityBundleBase implements WebformInterface {
|
|||
return $this->getSetting('form_confidential');
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function hasRemoteAddr() {
|
||||
return (!$this->isConfidential() && $this->getSetting('form_remote_addr')) ? TRUE : FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
|
@ -875,6 +912,7 @@ class Webform extends ConfigEntityBundleBase implements WebformInterface {
|
|||
'form_previous_submissions' => TRUE,
|
||||
'form_confidential' => FALSE,
|
||||
'form_confidential_message' => '',
|
||||
'form_remote_addr' => TRUE,
|
||||
'form_convert_anonymous' => FALSE,
|
||||
'form_prepopulate' => FALSE,
|
||||
'form_prepopulate_source_entity' => FALSE,
|
||||
|
@ -1112,6 +1150,22 @@ class Webform extends ConfigEntityBundleBase implements WebformInterface {
|
|||
return $selectors;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getElementsSelectorSourceValues() {
|
||||
/** @var \Drupal\webform\Plugin\WebformElementManagerInterface $element_manager */
|
||||
$element_manager = \Drupal::service('plugin.manager.webform.element');
|
||||
|
||||
$source_values = [];
|
||||
$elements = $this->getElementsInitializedAndFlattened();
|
||||
foreach ($elements as $element) {
|
||||
$element_plugin = $element_manager->getElementInstance($element);
|
||||
$source_values += $element_plugin->getElementSelectorSourceValues($element);
|
||||
}
|
||||
return $source_values;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
|
@ -1243,6 +1297,15 @@ class Webform extends ConfigEntityBundleBase implements WebformInterface {
|
|||
WebformElementHelper::applyTranslation($element, $this->elementsTranslations[$key]);
|
||||
}
|
||||
|
||||
// Prevent regressions where webform_computed_* element is still using
|
||||
// #value instead of #template.
|
||||
if (isset($element['#type']) && strpos($element['#type'], 'webform_computed_') === 0) {
|
||||
if (isset($element['#value']) && !isset($element['#template'])) {
|
||||
$element['#template'] = $element['#value'];
|
||||
unset($element['#value']);
|
||||
}
|
||||
}
|
||||
|
||||
// Copy only the element properties to decoded and flattened elements.
|
||||
$this->elementsDecodedAndFlattened[$key] = WebformElementHelper::getProperties($element);
|
||||
|
||||
|
@ -1701,6 +1764,7 @@ class Webform extends ConfigEntityBundleBase implements WebformInterface {
|
|||
|
||||
// Delete all submission associated with this webform.
|
||||
$submission_ids = \Drupal::entityQuery('webform_submission')
|
||||
->accessCheck(FALSE)
|
||||
->condition('webform_id', array_keys($entities), 'IN')
|
||||
->sort('sid')
|
||||
->execute();
|
||||
|
@ -1751,6 +1815,23 @@ class Webform extends ConfigEntityBundleBase implements WebformInterface {
|
|||
return $cache_contexts;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getCacheMaxAge() {
|
||||
if ($this->isScheduled()) {
|
||||
$time = time();
|
||||
if ($this->open && strtotime($this->open) > $time) {
|
||||
return (strtotime($this->open) - $time);
|
||||
}
|
||||
elseif ($this->close && strtotime($this->close) > $time) {
|
||||
return (strtotime($this->close) - $time);
|
||||
}
|
||||
}
|
||||
|
||||
return parent::getCacheMaxAge();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
|
@ -1845,37 +1926,37 @@ class Webform extends ConfigEntityBundleBase implements WebformInterface {
|
|||
return;
|
||||
}
|
||||
|
||||
$submit_base_path = '/' . ($page_submit_path ?: $default_page_base_path . '/' . str_replace('_', '-', $this->id()));
|
||||
|
||||
// Update submit path.
|
||||
$submit_suffixes = [
|
||||
'',
|
||||
'/submissions',
|
||||
'/drafts',
|
||||
];
|
||||
foreach ($submit_suffixes as $submit_suffix) {
|
||||
$submit_source = '/webform/' . $this->id() . $submit_suffix;
|
||||
$submit_alias = $submit_base_path . $submit_suffix;
|
||||
$this->updatePath($submit_source, $submit_alias, $this->langcode);
|
||||
$this->updatePath($submit_source, $submit_alias, LanguageInterface::LANGCODE_NOT_SPECIFIED);
|
||||
// Update webform base, confirmation, submissions and drafts paths.
|
||||
$path_base_alias = '/' . ($page_submit_path ?: $default_page_base_path . '/' . str_replace('_', '-', $this->id()));
|
||||
$path_suffixes = ['', '/confirmation', '/submissions', '/drafts'];
|
||||
foreach ($path_suffixes as $path_suffix) {
|
||||
$path_source = '/webform/' . $this->id() . $path_suffix;
|
||||
$path_alias = $path_base_alias . $path_suffix;
|
||||
if ($path_suffix === '/confirmation' && $this->settings['page_confirm_path']) {
|
||||
$path_alias = '/' . trim($this->settings['page_confirm_path'], '/');
|
||||
}
|
||||
$this->updatePath($path_source, $path_alias, $this->langcode);
|
||||
$this->updatePath($path_source, $path_alias, LanguageInterface::LANGCODE_NOT_SPECIFIED);
|
||||
}
|
||||
|
||||
// Update confirm path.
|
||||
$confirm_source = '/webform/' . $this->id() . '/confirmation';
|
||||
$confirm_alias = $this->settings['page_confirm_path'] ?: $submit_base_path . '/confirmation';
|
||||
$confirm_alias = '/' . trim($confirm_alias, '/');
|
||||
$this->updatePath($confirm_source, $confirm_alias, $this->langcode);
|
||||
$this->updatePath($confirm_source, $confirm_alias, LanguageInterface::LANGCODE_NOT_SPECIFIED);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function deletePaths() {
|
||||
// Path module must be enabled for URL aliases to be updated.
|
||||
if (!\Drupal::moduleHandler()->moduleExists('path')) {
|
||||
return;
|
||||
}
|
||||
|
||||
/** @var \Drupal\Core\Path\AliasStorageInterface $path_alias_storage */
|
||||
$path_alias_storage = \Drupal::service('path.alias_storage');
|
||||
$path_alias_storage->delete(['source' => '/webform/' . $this->id()]);
|
||||
$path_alias_storage->delete(['source' => '/webform/' . $this->id() . '/confirmation']);
|
||||
|
||||
// Delete webform base, confirmation, submissions and drafts paths.
|
||||
$path_suffixes = ['', '/confirmation', '/submissions', '/drafts'];
|
||||
foreach ($path_suffixes as $path_suffix) {
|
||||
$path_alias_storage->delete(['source' => '/webform/' . $this->id() . $path_suffix]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -47,6 +47,7 @@ use Drupal\webform\WebformSubmissionInterface;
|
|||
* },
|
||||
* bundle_entity_type = "webform",
|
||||
* list_cache_contexts = { "user" },
|
||||
* list_cache_tags = { "config:webform_list", "webform_submission_list" },
|
||||
* base_table = "webform_submission",
|
||||
* admin_permission = "administer webform",
|
||||
* entity_keys = {
|
||||
|
@ -707,7 +708,7 @@ class WebformSubmission extends ContentEntityBase implements WebformSubmissionIn
|
|||
'langcode' => \Drupal::languageManager()->getCurrentLanguage()->getId(),
|
||||
'token' => Crypt::randomBytesBase64(),
|
||||
'uri' => preg_replace('#^' . base_path() . '#', '/', $current_request->getRequestUri()),
|
||||
'remote_addr' => ($webform && $webform->isConfidential()) ? '' : $current_request->getClientIp(),
|
||||
'remote_addr' => ($webform && $webform->hasRemoteAddr()) ? '' : $current_request->getClientIp(),
|
||||
];
|
||||
|
||||
$webform->invokeHandlers(__FUNCTION__, $values);
|
||||
|
@ -749,7 +750,7 @@ class WebformSubmission extends ContentEntityBase implements WebformSubmissionIn
|
|||
*/
|
||||
public function save() {
|
||||
// Clear the remote_addr for confidential submissions.
|
||||
if ($this->getWebform()->isConfidential()) {
|
||||
if (!$this->getWebform()->hasRemoteAddr()) {
|
||||
$this->get('remote_addr')->value = '';
|
||||
}
|
||||
|
||||
|
|
|
@ -4,6 +4,7 @@ namespace Drupal\webform\EntitySettings;
|
|||
|
||||
use Drupal\Core\Cache\Cache;
|
||||
use Drupal\Core\Form\FormStateInterface;
|
||||
use Drupal\webform\Element\WebformMessage;
|
||||
|
||||
/**
|
||||
* Webform CSS and JS assets.
|
||||
|
@ -21,6 +22,8 @@ class WebformEntitySettingsAssetsForm extends WebformEntitySettingsBaseForm {
|
|||
'#type' => 'webform_message',
|
||||
'#message_message' => $this->t('The below CSS and JavasScript will be loaded on all pages that references and loads this webform.'),
|
||||
'#message_type' => 'info',
|
||||
'#message_close' => TRUE,
|
||||
'#message_storage' => WebformMessage::STORAGE_SESSION,
|
||||
];
|
||||
$form['css'] = [
|
||||
'#type' => 'fieldset',
|
||||
|
|
|
@ -4,6 +4,7 @@ namespace Drupal\webform\EntitySettings;
|
|||
|
||||
use Drupal\Core\Datetime\DrupalDateTime;
|
||||
use Drupal\Core\Form\FormStateInterface;
|
||||
use Drupal\webform\Element\WebformMessage;
|
||||
use Drupal\webform\Utility\WebformArrayHelper;
|
||||
use Drupal\webform\Utility\WebformDateHelper;
|
||||
use Drupal\webform\Utility\WebformElementHelper;
|
||||
|
@ -80,6 +81,21 @@ class WebformEntitySettingsFormForm extends WebformEntitySettingsBaseForm {
|
|||
],
|
||||
],
|
||||
];
|
||||
$t_args = [
|
||||
':page_cache_href' => 'https://www.drupal.org/docs/8/administering-a-drupal-8-site/internal-page-cache',
|
||||
':issue_href' => 'https://www.drupal.org/node/2352009',
|
||||
':cache_control_override_href' => 'https://www.drupal.org/project/cache_control_override',
|
||||
];
|
||||
if ($this->moduleHandler->moduleExists('page_cache') && !$this->moduleHandler->moduleExists('cache_control_override')) {
|
||||
$form['form_settings']['scheduled']['page_cache'] = [
|
||||
'#type' => 'webform_message',
|
||||
'#message_type' => 'warning',
|
||||
'#message_close' => TRUE,
|
||||
'#message_storage' => WebformMessage::STORAGE_SESSION,
|
||||
'#message_message' => $this->t('Scheduled forms do not work as expected for anonymous users when Drupal\'s <a href=":page_cache_href">Internal Page Cache</a> module is enabled. This is a <a href=":issue_href">known issue</a>.', $t_args) . '<br/><br/>' .
|
||||
'<strong>' . $this->t('It is strongly recommended that you install the <a href=":cache_control_override_href">Cache Control Override</a> module.', $t_args) . '</strong>',
|
||||
];
|
||||
}
|
||||
$form['form_settings']['scheduled']['open'] = [
|
||||
'#type' => 'datetime',
|
||||
'#title' => $this->t('Open'),
|
||||
|
|
|
@ -110,7 +110,7 @@ class WebformEntitySettingsGeneralForm extends WebformEntitySettingsBaseForm {
|
|||
];
|
||||
$form['general_settings']['archive'] = [
|
||||
'#type' => 'checkbox',
|
||||
'#title' => $this->t('Archived this webform'),
|
||||
'#title' => $this->t('Archive this webform'),
|
||||
'#description' => $this->t('If checked, this webform will be closed and unavailable to webform blocks and fields.'),
|
||||
'#return_value' => TRUE,
|
||||
'#default_value' => $webform->isArchived(),
|
||||
|
@ -250,11 +250,6 @@ class WebformEntitySettingsGeneralForm extends WebformEntitySettingsBaseForm {
|
|||
'#title' => $this->t('Ajax settings'),
|
||||
'#open' => TRUE,
|
||||
'#access' => empty($elements['#method']),
|
||||
'#states' => [
|
||||
'visible' => [
|
||||
':input[name="method"]' => ['value' => ''],
|
||||
],
|
||||
],
|
||||
];
|
||||
$form['ajax_settings']['ajax'] = [
|
||||
'#type' => 'checkbox',
|
||||
|
|
|
@ -277,6 +277,19 @@ class WebformEntitySettingsSubmissionsForm extends WebformEntitySettingsBaseForm
|
|||
],
|
||||
'#weight' => -99,
|
||||
];
|
||||
$form['submission_behaviors']['form_remote_addr'] = [
|
||||
'#type' => 'checkbox',
|
||||
'#title' => $this->t('Track user IP address'),
|
||||
'#description' => $this->t("If checked, a user's IP address will be recorded."),
|
||||
'#return_value' => TRUE,
|
||||
'#default_value' => $settings['form_remote_addr'],
|
||||
'#states' => [
|
||||
'visible' => [
|
||||
':input[name="form_confidential"]' => ['checked' => FALSE],
|
||||
],
|
||||
],
|
||||
'#weight' => -98,
|
||||
];
|
||||
$form['submission_behaviors']['form_convert_anonymous'] = [
|
||||
'#type' => 'checkbox',
|
||||
'#title' => $this->t('Convert anonymous user drafts and submissions to authenticated user'),
|
||||
|
@ -288,7 +301,7 @@ class WebformEntitySettingsSubmissionsForm extends WebformEntitySettingsBaseForm
|
|||
':input[name="form_confidential"]' => ['checked' => FALSE],
|
||||
],
|
||||
],
|
||||
'#weight' => -98,
|
||||
'#weight' => -97,
|
||||
];
|
||||
$behavior_elements = [
|
||||
// Form specific behaviors.
|
||||
|
|
|
@ -12,12 +12,13 @@ use Drupal\Core\Session\AccountInterface;
|
|||
use Drupal\Core\Render\RendererInterface;
|
||||
use Drupal\Core\StringTranslation\StringTranslationTrait;
|
||||
use Drupal\Core\Url;
|
||||
use Psr\Log\LoggerInterface;
|
||||
use Drupal\webform\Element\WebformHtmlEditor;
|
||||
use Drupal\webform\Entity\Webform;
|
||||
use Drupal\webform\Entity\WebformSubmission;
|
||||
use Drupal\webform\WebformInterface;
|
||||
use Drupal\webform\WebformTokenManagerInterface;
|
||||
use Psr\Log\LoggerInterface;
|
||||
use Symfony\Component\HttpKernel\Exception\HttpExceptionInterface;
|
||||
use Symfony\Component\HttpFoundation\RedirectResponse;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
use Symfony\Component\HttpKernel\Event\GetResponseForExceptionEvent;
|
||||
|
@ -102,9 +103,9 @@ class WebformExceptionHtmlSubscriber extends DefaultExceptionHtmlSubscriber {
|
|||
* {@inheritdoc}
|
||||
*/
|
||||
protected static function getPriority() {
|
||||
// Execute before CustomPageExceptionHtmlSubscriber which is -128.
|
||||
// @see \Drupal\Core\EventSubscriber\CustomPageExceptionHtmlSubscriber
|
||||
return -127;
|
||||
// Execute before CustomPageExceptionHtmlSubscriber which is -50.
|
||||
// @see \Drupal\Core\EventSubscriber\CustomPageExceptionHtmlSubscriber::getPriority
|
||||
return -49;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -256,6 +257,18 @@ class WebformExceptionHtmlSubscriber extends DefaultExceptionHtmlSubscriber {
|
|||
return ['html'];
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function onException(GetResponseForExceptionEvent $event) {
|
||||
// Only handle 403 exception.
|
||||
// @see \Drupal\webform\EventSubscriber\WebformExceptionHtmlSubscriber::on403
|
||||
$exception = $event->getException();
|
||||
if ($exception instanceof HttpExceptionInterface && $exception->getStatusCode() === 403) {
|
||||
parent::onException($event);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Redirect to user login with destination and display custom message.
|
||||
*
|
||||
|
|
|
@ -8,6 +8,7 @@ use Drupal\Core\Extension\ModuleHandlerInterface;
|
|||
use Drupal\Core\Form\FormStateInterface;
|
||||
use Drupal\Core\Routing\RouteBuilderInterface;
|
||||
use Drupal\Core\Url;
|
||||
use Drupal\webform\Commands\WebformCliService;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
|
||||
/**
|
||||
|
@ -36,6 +37,13 @@ class WebformAdminConfigAdvancedForm extends WebformAdminConfigBaseForm {
|
|||
*/
|
||||
protected $routerBuilder;
|
||||
|
||||
/**
|
||||
* The (drush) command-line service.
|
||||
*
|
||||
* @var \Drupal\webform\Commands\WebformCliService
|
||||
*/
|
||||
protected $cliService;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
|
@ -54,12 +62,15 @@ class WebformAdminConfigAdvancedForm extends WebformAdminConfigBaseForm {
|
|||
* The render cache service.
|
||||
* @param \Drupal\Core\Routing\RouteBuilderInterface $router_builder
|
||||
* The router builder service.
|
||||
* @param \Drupal\webform\Commands\WebformCliService $cli_service
|
||||
* The (drush) command-line service.
|
||||
*/
|
||||
public function __construct(ConfigFactoryInterface $config_factory, ModuleHandlerInterface $module_handler, CacheBackendInterface $render_cache, RouteBuilderInterface $router_builder) {
|
||||
public function __construct(ConfigFactoryInterface $config_factory, ModuleHandlerInterface $module_handler, CacheBackendInterface $render_cache, RouteBuilderInterface $router_builder, WebformCliService $cli_service) {
|
||||
parent::__construct($config_factory);
|
||||
$this->renderCache = $render_cache;
|
||||
$this->moduleHandler = $module_handler;
|
||||
$this->routerBuilder = $router_builder;
|
||||
$this->cliService = $cli_service;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -70,7 +81,8 @@ class WebformAdminConfigAdvancedForm extends WebformAdminConfigBaseForm {
|
|||
$container->get('config.factory'),
|
||||
$container->get('module_handler'),
|
||||
$container->get('cache.render'),
|
||||
$container->get('router.builder')
|
||||
$container->get('router.builder'),
|
||||
$container->get('webform.cli_service')
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -252,6 +264,24 @@ class WebformAdminConfigAdvancedForm extends WebformAdminConfigBaseForm {
|
|||
'#default_value' => $config->get('batch.default_batch_email_size'),
|
||||
];
|
||||
|
||||
// Repair.
|
||||
$form['repair'] = [
|
||||
'#type' => 'details',
|
||||
'#title' => $this->t('Repair webform configuration'),
|
||||
'#open' => TRUE,
|
||||
'#description' => '<p>' . $this->t('If older Webform configuration files are imported after the Webform module has been updated this may cause the older configuration to be out-of-sync and result in unexpected behaviors and errors.') . '</p>' .
|
||||
'<p>' . $this->t("Running the below 'Repair' command will apply all missing settings to older Webform configuration files.") . '</p>',
|
||||
'#help' => FALSE,
|
||||
];
|
||||
$form['repair']['action'] = ['#type' => 'actions'];
|
||||
$form['repair']['action']['repair_configuration'] = [
|
||||
'#type' => 'submit',
|
||||
'#value' => $this->t('Repair configuration'),
|
||||
'#attributes' => [
|
||||
'onclick' => 'return confirm("' . $this->t('Are you sure you want to repair webform configuration?') . '\n' . $this->t('This cannot be undone!!!') . '");',
|
||||
],
|
||||
];
|
||||
|
||||
return parent::buildForm($form, $form_state);
|
||||
}
|
||||
|
||||
|
@ -259,33 +289,62 @@ class WebformAdminConfigAdvancedForm extends WebformAdminConfigBaseForm {
|
|||
* {@inheritdoc}
|
||||
*/
|
||||
public function submitForm(array &$form, FormStateInterface $form_state) {
|
||||
// Update config and submit form.
|
||||
$config = $this->config('webform.settings');
|
||||
$config->set('ui', $form_state->getValue('ui'));
|
||||
$config->set('requirements', $form_state->getValue('requirements'));
|
||||
$config->set('test', $form_state->getValue('test'));
|
||||
$config->set('batch', $form_state->getValue('batch'));
|
||||
$op = (string) $form_state->getValue('op');
|
||||
if ($op === (string) $this->t('Repair configuration')) {
|
||||
// Copied from:
|
||||
// @see \Drupal\webform\Commands\WebformCliService::drush_webform_repair
|
||||
module_load_include('install', 'webform');
|
||||
|
||||
// Track if help is disabled.
|
||||
// @todo Figure out how to clear cached help block.
|
||||
$is_help_disabled = ($config->getOriginal('ui.help_disabled') != $config->get('ui.help_disabled'));
|
||||
$this->messenger()->addMessage($this->t('Repairing webform submission storage schema…'));
|
||||
_webform_update_webform_submission_storage_schema();
|
||||
|
||||
parent::submitForm($form, $form_state);
|
||||
$this->messenger()->addMessage($this->t('Repairing admin settings…'));
|
||||
_webform_update_admin_settings(TRUE);
|
||||
|
||||
$this->messenger()->addMessage($this->t('Repairing webform settings…'));
|
||||
_webform_update_webform_settings();
|
||||
|
||||
$this->messenger()->addMessage($this->t('Repairing webform handlers…'));
|
||||
_webform_update_webform_handler_settings();
|
||||
|
||||
$this->messenger()->addMessage($this->t('Repairing webform field storage definitions…'));
|
||||
_webform_update_field_storage_definitions();
|
||||
|
||||
$this->messenger()->addMessage($this->t('Repairing webform submission storage schema…'));
|
||||
_webform_update_webform_submission_storage_schema();
|
||||
|
||||
// Clear cached data.
|
||||
if ($is_help_disabled) {
|
||||
// Flush cache when help is being enabled.
|
||||
// @see webform_help()
|
||||
drupal_flush_all_caches();
|
||||
|
||||
$this->messenger()->addStatus($this->t('Webform configuration has been repaired.'));
|
||||
}
|
||||
else {
|
||||
// Clear render cache so that local tasks can be updated to hide/show
|
||||
// the 'Contribute' tab.
|
||||
// @see webform_local_tasks_alter()
|
||||
$this->renderCache->deleteAll();
|
||||
$this->routerBuilder->rebuild();
|
||||
}
|
||||
// Update config and submit form.
|
||||
$config = $this->config('webform.settings');
|
||||
$config->set('ui', $form_state->getValue('ui'));
|
||||
$config->set('requirements', $form_state->getValue('requirements'));
|
||||
$config->set('test', $form_state->getValue('test'));
|
||||
$config->set('batch', $form_state->getValue('batch'));
|
||||
|
||||
// Track if help is disabled.
|
||||
// @todo Figure out how to clear cached help block.
|
||||
$is_help_disabled = ($config->getOriginal('ui.help_disabled') != $config->get('ui.help_disabled'));
|
||||
|
||||
parent::submitForm($form, $form_state);
|
||||
|
||||
// Clear cached data.
|
||||
if ($is_help_disabled) {
|
||||
// Flush cache when help is being enabled.
|
||||
// @see webform_help()
|
||||
drupal_flush_all_caches();
|
||||
}
|
||||
else {
|
||||
// Clear render cache so that local tasks can be updated to hide/show
|
||||
// the 'Contribute' tab.
|
||||
// @see webform_local_tasks_alter()
|
||||
$this->renderCache->deleteAll();
|
||||
$this->routerBuilder->rebuild();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
namespace Drupal\webform\Form\AdminConfig;
|
||||
|
||||
use Drupal\Core\Config\ConfigFactoryInterface;
|
||||
use Drupal\Core\Extension\ModuleHandlerInterface;
|
||||
use Drupal\Core\Form\FormStateInterface;
|
||||
use Drupal\webform\Plugin\WebformHandlerManagerInterface;
|
||||
use Drupal\webform\WebformTokenManagerInterface;
|
||||
|
@ -13,6 +14,13 @@ use Symfony\Component\DependencyInjection\ContainerInterface;
|
|||
*/
|
||||
class WebformAdminConfigHandlersForm extends WebformAdminConfigBaseForm {
|
||||
|
||||
/**
|
||||
* The module handler.
|
||||
*
|
||||
* @var \Drupal\Core\Extension\ModuleHandlerInterface
|
||||
*/
|
||||
protected $moduleHandler;
|
||||
|
||||
/**
|
||||
* The webform token manager.
|
||||
*
|
||||
|
@ -39,13 +47,16 @@ class WebformAdminConfigHandlersForm extends WebformAdminConfigBaseForm {
|
|||
*
|
||||
* @param \Drupal\Core\Config\ConfigFactoryInterface $config_factory
|
||||
* The factory for configuration objects.
|
||||
* @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler
|
||||
* The module handler.
|
||||
* @param \Drupal\webform\WebformTokenManagerInterface $token_manager
|
||||
* The webform token manager.
|
||||
* @param \Drupal\webform\Plugin\WebformHandlerManagerInterface $handler_manager
|
||||
* The webform handler manager.
|
||||
*/
|
||||
public function __construct(ConfigFactoryInterface $config_factory, WebformTokenManagerInterface $token_manager, WebformHandlerManagerInterface $handler_manager) {
|
||||
public function __construct(ConfigFactoryInterface $config_factory, ModuleHandlerInterface $module_handler, WebformTokenManagerInterface $token_manager, WebformHandlerManagerInterface $handler_manager) {
|
||||
parent::__construct($config_factory);
|
||||
$this->moduleHandler = $module_handler;
|
||||
$this->tokenManager = $token_manager;
|
||||
$this->handlerManager = $handler_manager;
|
||||
}
|
||||
|
@ -56,6 +67,7 @@ class WebformAdminConfigHandlersForm extends WebformAdminConfigBaseForm {
|
|||
public static function create(ContainerInterface $container) {
|
||||
return new static(
|
||||
$container->get('config.factory'),
|
||||
$container->get('module_handler'),
|
||||
$container->get('webform.token_manager'),
|
||||
$container->get('plugin.manager.webform.handler')
|
||||
);
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
namespace Drupal\webform\Form\AdminConfig;
|
||||
|
||||
use Drupal\Core\Config\ConfigFactoryInterface;
|
||||
use Drupal\Core\Extension\ModuleHandlerInterface;
|
||||
use Drupal\Core\Form\FormStateInterface;
|
||||
use Drupal\webform\Element\WebformMessage;
|
||||
use Drupal\webform\WebformTokenManagerInterface;
|
||||
|
@ -13,6 +14,13 @@ use Symfony\Component\DependencyInjection\ContainerInterface;
|
|||
*/
|
||||
class WebformAdminConfigSubmissionsForm extends WebformAdminConfigBaseForm {
|
||||
|
||||
/**
|
||||
* The module handler.
|
||||
*
|
||||
* @var \Drupal\Core\Extension\ModuleHandlerInterface
|
||||
*/
|
||||
protected $moduleHandler;
|
||||
|
||||
/**
|
||||
* The webform token manager.
|
||||
*
|
||||
|
@ -32,11 +40,14 @@ class WebformAdminConfigSubmissionsForm extends WebformAdminConfigBaseForm {
|
|||
*
|
||||
* @param \Drupal\Core\Config\ConfigFactoryInterface $config_factory
|
||||
* The factory for configuration objects.
|
||||
* @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler
|
||||
* The module handler.
|
||||
* @param \Drupal\webform\WebformTokenManagerInterface $token_manager
|
||||
* The webform token manager.
|
||||
*/
|
||||
public function __construct(ConfigFactoryInterface $config_factory, WebformTokenManagerInterface $token_manager) {
|
||||
public function __construct(ConfigFactoryInterface $config_factory, ModuleHandlerInterface $module_handler, WebformTokenManagerInterface $token_manager) {
|
||||
parent::__construct($config_factory);
|
||||
$this->moduleHandler = $module_handler;
|
||||
$this->tokenManager = $token_manager;
|
||||
}
|
||||
|
||||
|
@ -46,6 +57,7 @@ class WebformAdminConfigSubmissionsForm extends WebformAdminConfigBaseForm {
|
|||
public static function create(ContainerInterface $container) {
|
||||
return new static(
|
||||
$container->get('config.factory'),
|
||||
$container->get('module_handler'),
|
||||
$container->get('webform.token_manager')
|
||||
);
|
||||
}
|
||||
|
@ -118,7 +130,8 @@ class WebformAdminConfigSubmissionsForm extends WebformAdminConfigBaseForm {
|
|||
$behavior_elements = [
|
||||
'default_submission_log' => [
|
||||
'title' => $this->t('Log all submission events for all webforms'),
|
||||
'description' => $this->t('If checked, all submission events will be logged to dedicated submission log available to all webforms and submissions.'),
|
||||
'description' => $this->t('If checked, all submission events will be logged to dedicated submission log available to all webforms and submissions.') . '<br/><br/>' .
|
||||
'<em>' . t('The webform submission log will track more detailed user information including email addresses and subjects.') . '</em>',
|
||||
],
|
||||
];
|
||||
foreach ($behavior_elements as $behavior_key => $behavior_element) {
|
||||
|
@ -130,6 +143,20 @@ class WebformAdminConfigSubmissionsForm extends WebformAdminConfigBaseForm {
|
|||
'#default_value' => $settings[$behavior_key],
|
||||
];
|
||||
}
|
||||
if (!$this->moduleHandler->moduleExists('webform_submission_log')) {
|
||||
$form['submission_behaviors']['webform_submission_log_message'] = [
|
||||
'#type' => 'webform_message',
|
||||
'#message_type' => 'info',
|
||||
'#message_message' => $this->t("Enable the 'Webform Submission Log' module to better track and permanently store submission logs."),
|
||||
'#message_close' => TRUE,
|
||||
'#message_storage' => WebformMessage::STORAGE_SESSION,
|
||||
'#states' => [
|
||||
'visible' => [
|
||||
':input[name="submission_behaviors[default_submission_log]"]' => ['checked' => TRUE],
|
||||
],
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
// Submission limits.
|
||||
$form['submission_limits'] = [
|
||||
|
|
|
@ -10,7 +10,7 @@ use Drupal\Core\Form\FormStateInterface;
|
|||
/**
|
||||
* Provides a generic base class for a webform entity deletion form.
|
||||
*
|
||||
* Copied from: \Drupal\Core\Entity\EntityConfirmFormBase
|
||||
* Copied from: \Drupal\Core\Entity\EntityConfirmFormBase.
|
||||
*/
|
||||
abstract class WebformConfigEntityDeleteFormBase extends EntityForm implements WebformDeleteFormInterface {
|
||||
|
||||
|
|
|
@ -2,7 +2,6 @@
|
|||
|
||||
namespace Drupal\webform\Form;
|
||||
|
||||
use Drupal\Core\Cache\CacheBackendInterface;
|
||||
use Drupal\Core\Ajax\AjaxResponse;
|
||||
use Drupal\Core\Ajax\HtmlCommand;
|
||||
use Drupal\Core\Ajax\RedirectCommand;
|
||||
|
@ -11,7 +10,6 @@ use Drupal\Core\Config\ConfigFactoryInterface;
|
|||
use Drupal\Core\EventSubscriber\MainContentViewSubscriber;
|
||||
use Drupal\Core\Form\ConfigFormBase;
|
||||
use Drupal\Core\Form\FormStateInterface;
|
||||
use Drupal\Core\Routing\RouteBuilderInterface;
|
||||
use Drupal\Core\Url;
|
||||
use Drupal\webform\WebformContributeManagerInterface;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
|
@ -21,20 +19,6 @@ use Symfony\Component\DependencyInjection\ContainerInterface;
|
|||
*/
|
||||
class WebformContributeForm extends ConfigFormBase {
|
||||
|
||||
/**
|
||||
* The render cache bin.
|
||||
*
|
||||
* @var \Drupal\Core\Cache\CacheBackendInterface
|
||||
*/
|
||||
protected $renderCache;
|
||||
|
||||
/**
|
||||
* The router builder.
|
||||
*
|
||||
* @var \Drupal\Core\Routing\RouteBuilderInterface
|
||||
*/
|
||||
protected $routerBuilder;
|
||||
|
||||
/**
|
||||
* The contribute manager.
|
||||
*
|
||||
|
@ -57,21 +41,15 @@ class WebformContributeForm extends ConfigFormBase {
|
|||
}
|
||||
|
||||
/**
|
||||
* Constructs a ContributeSettingsForm object.
|
||||
* Constructs a WebformContributeForm object.
|
||||
*
|
||||
* @param \Drupal\Core\Config\ConfigFactoryInterface $config_factory
|
||||
* The factory for configuration objects.
|
||||
* @param \Drupal\Core\Cache\CacheBackendInterface $render_cache
|
||||
* The render cache service.
|
||||
* @param \Drupal\Core\Routing\RouteBuilderInterface $router_builder
|
||||
* The router builder service.
|
||||
* @param \Drupal\webform\WebformContributeManagerInterface $contribute_manager
|
||||
* The contribute manager.
|
||||
*/
|
||||
public function __construct(ConfigFactoryInterface $config_factory, CacheBackendInterface $render_cache, RouteBuilderInterface $router_builder, WebformContributeManagerInterface $contribute_manager) {
|
||||
public function __construct(ConfigFactoryInterface $config_factory, WebformContributeManagerInterface $contribute_manager) {
|
||||
parent::__construct($config_factory);
|
||||
$this->renderCache = $render_cache;
|
||||
$this->routerBuilder = $router_builder;
|
||||
$this->contributeManager = $contribute_manager;
|
||||
}
|
||||
|
||||
|
@ -81,8 +59,6 @@ class WebformContributeForm extends ConfigFormBase {
|
|||
public static function create(ContainerInterface $container) {
|
||||
return new static(
|
||||
$container->get('config.factory'),
|
||||
$container->get('cache.render'),
|
||||
$container->get('router.builder'),
|
||||
$container->get('webform.contribute_manager')
|
||||
);
|
||||
}
|
||||
|
|
|
@ -9,7 +9,7 @@ use Drupal\webform\WebformInterface;
|
|||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
|
||||
/**
|
||||
* Provides the webform filter webform.
|
||||
* Provides the webform filter form.
|
||||
*/
|
||||
class WebformEntityFilterForm extends FormBase {
|
||||
|
||||
|
|
|
@ -86,14 +86,16 @@ class WebformHelpVideoForm extends FormBase {
|
|||
}
|
||||
|
||||
// Related resources.
|
||||
$form['resources'] = [
|
||||
'#type' => 'details',
|
||||
'#title' => $this->t('Additional resources'),
|
||||
'links' => [
|
||||
'#theme' => 'links',
|
||||
'#links' => $this->helpManager->getVideoLinks($this->videoId),
|
||||
],
|
||||
];
|
||||
if ($video_links = $this->helpManager->getVideoLinks($this->videoId)) {
|
||||
$form['resources'] = [
|
||||
'#type' => 'details',
|
||||
'#title' => $this->t('Additional resources'),
|
||||
'links' => [
|
||||
'#theme' => 'links',
|
||||
'#links' => $video_links,
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
// Actions.
|
||||
if (isset($video['submit_label'])) {
|
||||
|
|
|
@ -0,0 +1,88 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\webform\Form;
|
||||
|
||||
use Drupal\Core\Form\FormBase;
|
||||
use Drupal\Core\Form\FormStateInterface;
|
||||
|
||||
/**
|
||||
* Provides the webform options filter form.
|
||||
*/
|
||||
class WebformOptionsFilterForm extends FormBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getFormId() {
|
||||
return 'webform_options_filter_form';
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function buildForm(array $form, FormStateInterface $form_state, $search = NULL, $category = NULL, array $categories = []) {
|
||||
$form['#attributes'] = ['class' => ['webform-filter-form']];
|
||||
$form['filter'] = [
|
||||
'#type' => 'details',
|
||||
'#title' => $this->t('Filter options'),
|
||||
'#open' => TRUE,
|
||||
'#attributes' => ['class' => ['container-inline']],
|
||||
];
|
||||
$form['filter']['search'] = [
|
||||
'#type' => 'search',
|
||||
'#title' => $this->t('Keyword'),
|
||||
'#title_display' => 'invisible',
|
||||
'#autocomplete_route_name' => 'entity.webform_options.autocomplete',
|
||||
'#placeholder' => $this->t('Filter by title or options'),
|
||||
'#size' => 45,
|
||||
'#default_value' => $search,
|
||||
];
|
||||
$form['filter']['category'] = [
|
||||
'#type' => 'select',
|
||||
'#title' => $this->t('Category'),
|
||||
'#title_display' => 'invisible',
|
||||
'#options' => $categories,
|
||||
'#empty_option' => ($category) ? $this->t('Show all options') : $this->t('Filter by category'),
|
||||
'#default_value' => $category,
|
||||
];
|
||||
$form['filter']['submit'] = [
|
||||
'#type' => 'submit',
|
||||
'#button_type' => 'primary',
|
||||
'#value' => $this->t('Filter'),
|
||||
];
|
||||
if (!empty($search) || !empty($category)) {
|
||||
$form['filter']['reset'] = [
|
||||
'#type' => 'submit',
|
||||
'#submit' => ['::resetForm'],
|
||||
'#value' => $this->t('Reset'),
|
||||
];
|
||||
}
|
||||
return $form;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function submitForm(array &$form, FormStateInterface $form_state) {
|
||||
$query = [
|
||||
'search' => trim($form_state->getValue('search')),
|
||||
'category' => trim($form_state->getValue('category')),
|
||||
];
|
||||
$form_state->setRedirect($this->getRouteMatch()->getRouteName(), $this->getRouteMatch()->getRawParameters()->all(), [
|
||||
'query' => $query ,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets the filter selection.
|
||||
*
|
||||
* @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.
|
||||
*/
|
||||
public function resetForm(array &$form, FormStateInterface $form_state) {
|
||||
$form_state->setRedirect($this->getRouteMatch()->getRouteName(), $this->getRouteMatch()->getRawParameters()->all());
|
||||
}
|
||||
|
||||
}
|
|
@ -157,8 +157,6 @@ class WebformResultsCustomForm extends FormBase {
|
|||
'100' => '100',
|
||||
'200' => '200',
|
||||
'500' => '500',
|
||||
'1000' => '1000',
|
||||
'0' => $this->t('All'),
|
||||
],
|
||||
'#default_value' => ($limit !== NULL) ? $limit : 20,
|
||||
];
|
||||
|
|
|
@ -7,7 +7,7 @@ use Drupal\Core\Form\FormStateInterface;
|
|||
use Drupal\webform\WebformInterface;
|
||||
|
||||
/**
|
||||
* Provides the webform submission filter webform.
|
||||
* Provides the webform submission filter form.
|
||||
*/
|
||||
class WebformSubmissionFilterForm extends FormBase {
|
||||
|
||||
|
|
|
@ -131,7 +131,8 @@ class Webform extends ConditionPluginBase implements ContainerFactoryPluginInter
|
|||
* {@inheritdoc}
|
||||
*/
|
||||
public function submitConfigurationForm(array &$form, FormStateInterface $form_state) {
|
||||
$this->configuration['webforms'] = array_filter($form_state->getValue('webforms'));
|
||||
$values = $form_state->getValue('webforms') ?: [];
|
||||
$this->configuration['webforms'] = array_filter($values);
|
||||
parent::submitConfigurationForm($form, $form_state);
|
||||
}
|
||||
|
||||
|
|
|
@ -154,20 +154,25 @@ class WebformEntityReferenceEntityFormatter extends WebformEntityReferenceFormat
|
|||
* {@inheritdoc}
|
||||
*/
|
||||
public function viewElements(FieldItemListInterface $items, $langcode) {
|
||||
// Get source entity.
|
||||
$source_entity = $items->getEntity();
|
||||
$source_entity = WebformSourceEntityManager::getMainSourceEntity($source_entity);
|
||||
// Get items entity, which is the entity that the webform
|
||||
// is directly attached to. For Paragraphs this would be the field's
|
||||
// paragraph entity.
|
||||
$items_entity = $items->getEntity();
|
||||
|
||||
// Determine if webform is previewed within a Paragraph on .edit_form
|
||||
// or .content_translation_add.
|
||||
// Get (main) source entity, which is the main parent entity for
|
||||
// a paragraph entity.
|
||||
$source_entity = WebformSourceEntityManager::getMainSourceEntity($items_entity);
|
||||
|
||||
// Determine if webform is previewed within a Paragraph on
|
||||
// node edit forms (via *.edit_form or .content_translation_add routes).
|
||||
$route = $this->routeMatch->getRouteName();
|
||||
$is_paragraph_edit_preview = ($source_entity->getEntityTypeId() === 'paragraph' &&
|
||||
preg_match('/\.edit_form$/', $route)
|
||||
|| preg_match('/\.content_translation_add$/', $route)
|
||||
) ? TRUE : FALSE;
|
||||
$is_node_edit = (preg_match('/\.edit_form$/', $route) || preg_match('/\.content_translation_add$/', $route));
|
||||
$is_paragraph = ($items_entity && $items_entity->getEntityTypeId() === 'paragraph');
|
||||
$is_paragraph_node_edit = ($is_paragraph && $is_node_edit);
|
||||
|
||||
$elements = [];
|
||||
foreach ($this->getEntitiesToView($items, $langcode) as $delta => $entity) {
|
||||
if ($is_paragraph_edit_preview) {
|
||||
if ($is_paragraph_node_edit) {
|
||||
// Webform can not be nested within node edit form because the nested
|
||||
// <form> tags will cause unexpected validation issues.
|
||||
$elements[$delta] = [
|
||||
|
|
|
@ -0,0 +1,52 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\webform\Plugin\Field\FieldFormatter;
|
||||
|
||||
use Drupal\Core\Field\FieldItemListInterface;
|
||||
|
||||
/**
|
||||
* Plugin implementation of the 'Webform url' formatter.
|
||||
*
|
||||
* @FieldFormatter(
|
||||
* id = "webform_entity_reference_url",
|
||||
* label = @Translation("URL"),
|
||||
* description = @Translation("Display URL to the referenced webform."),
|
||||
* field_types = {
|
||||
* "webform"
|
||||
* }
|
||||
* )
|
||||
*/
|
||||
class WebformEntityReferenceUrlFormatter extends WebformEntityReferenceFormatterBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function viewElements(FieldItemListInterface $items, $langcode) {
|
||||
$source_entity = $items->getEntity();
|
||||
|
||||
$elements = [];
|
||||
|
||||
/** @var \Drupal\webform\WebformInterface[] $entities */
|
||||
$entities = $this->getEntitiesToView($items, $langcode);
|
||||
|
||||
foreach ($entities as $delta => $entity) {
|
||||
$link_options = [
|
||||
'query' => [
|
||||
'source_entity_type' => $source_entity->getEntityTypeId(),
|
||||
'source_entity_id' => $source_entity->id(),
|
||||
],
|
||||
];
|
||||
|
||||
$link = [
|
||||
'#plain_text' => $entity->toUrl('canonical', $link_options)->toString(),
|
||||
];
|
||||
|
||||
$elements[$delta] = $link;
|
||||
|
||||
$this->setCacheContext($elements[$delta], $entity, $items[$delta]);
|
||||
}
|
||||
|
||||
return $elements;
|
||||
}
|
||||
|
||||
}
|
|
@ -6,6 +6,7 @@ use Drupal\Core\Entity\EntityTypeInterface;
|
|||
use Drupal\Core\Field\FieldStorageDefinitionInterface;
|
||||
use Drupal\Core\Field\Plugin\Field\FieldType\EntityReferenceItem;
|
||||
use Drupal\Core\Form\FormStateInterface;
|
||||
use Drupal\Core\Session\AccountInterface;
|
||||
use Drupal\Core\TypedData\DataDefinition;
|
||||
use Drupal\webform\WebformInterface;
|
||||
|
||||
|
@ -120,4 +121,13 @@ class WebformEntityReferenceItem extends EntityReferenceItem {
|
|||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getSettableOptions(AccountInterface $account = NULL) {
|
||||
/** @var \Drupal\webform\WebformEntityStorageInterface $webform_storage */
|
||||
$webform_storage = \Drupal::service('entity_type.manager')->getStorage('webform');
|
||||
return $webform_storage->getOptions(FALSE);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -2,12 +2,9 @@
|
|||
|
||||
namespace Drupal\webform\Plugin\Field\FieldWidget;
|
||||
|
||||
use Drupal\Core\Datetime\DrupalDateTime;
|
||||
use Drupal\Core\Field\FieldItemListInterface;
|
||||
use Drupal\Core\Field\Plugin\Field\FieldWidget\EntityReferenceAutocompleteWidget;
|
||||
use Drupal\Core\Form\FormStateInterface;
|
||||
use Drupal\webform\Utility\WebformDateHelper;
|
||||
use Drupal\webform\WebformInterface;
|
||||
|
||||
/**
|
||||
* Plugin implementation of the 'webform_entity_reference_autocomplete' widget.
|
||||
|
@ -23,225 +20,32 @@ use Drupal\webform\WebformInterface;
|
|||
*/
|
||||
class WebformEntityReferenceAutocompleteWidget extends EntityReferenceAutocompleteWidget {
|
||||
|
||||
use WebformEntityReferenceWidgetTrait;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function defaultSettings() {
|
||||
public function getTargetIdElement(FieldItemListInterface $items, $delta, array $element, array &$form, FormStateInterface $form_state) {
|
||||
// Get default value.
|
||||
$referenced_entities = $items->referencedEntities();
|
||||
$default_value = isset($referenced_entities[$delta]) ? $referenced_entities[$delta] : NULL;
|
||||
|
||||
// Append the match operation to the selection settings.
|
||||
$selection_settings = $this->getFieldSetting('handler_settings') + ['match_operator' => $this->getSetting('match_operator')];
|
||||
|
||||
return [
|
||||
'default_data' => TRUE,
|
||||
] + parent::defaultSettings();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function settingsForm(array $form, FormStateInterface $form_state) {
|
||||
$element = parent::settingsForm($form, $form_state);
|
||||
$element['default_data'] = [
|
||||
'#type' => 'checkbox',
|
||||
'#title' => t('Enable default submission data (YAML)'),
|
||||
'#description' => t('If checked, site builders will be able to define default submission data (YAML)'),
|
||||
'#default_value' => $this->getSetting('default_data'),
|
||||
'#type' => 'entity_autocomplete',
|
||||
'#target_type' => $this->getFieldSetting('target_type'),
|
||||
'#selection_handler' => $this->getFieldSetting('handler'),
|
||||
'#selection_settings' => $selection_settings,
|
||||
// Entity reference field items are handling validation themselves via
|
||||
// the 'ValidReference' constraint.
|
||||
'#validate_reference' => FALSE,
|
||||
'#maxlength' => 1024,
|
||||
'#default_value' => $default_value,
|
||||
'#size' => $this->getSetting('size'),
|
||||
'#placeholder' => $this->getSetting('placeholder'),
|
||||
];
|
||||
return $element;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function settingsSummary() {
|
||||
$summary = parent::settingsSummary();
|
||||
$summary[] = t('Default submission data: @default_data', ['@default_data' => $this->getSetting('default_data') ? $this->t('Yes') : $this->t('No')]);
|
||||
return $summary;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function formElement(FieldItemListInterface $items, $delta, array $element, array &$form, FormStateInterface $form_state) {
|
||||
if (!isset($items[$delta]->status)) {
|
||||
$items[$delta]->status = WebformInterface::STATUS_OPEN;
|
||||
}
|
||||
|
||||
$element = parent::formElement($items, $delta, $element, $form, $form_state);
|
||||
|
||||
// Get field name.
|
||||
$field_name = $items->getName();
|
||||
|
||||
// Get field input name from field parents, field name, and the delta.
|
||||
$field_parents = array_merge($element['target_id']['#field_parents'], [$field_name, $delta]);
|
||||
$field_input_name = (array_shift($field_parents)) . ('[' . implode('][', $field_parents) . ']');
|
||||
|
||||
// Set element 'target_id' default properties.
|
||||
$element['target_id'] += [
|
||||
'#weight' => 0,
|
||||
];
|
||||
|
||||
// Get weight.
|
||||
$weight = $element['target_id']['#weight'];
|
||||
|
||||
$element['settings'] = [
|
||||
'#type' => 'details',
|
||||
'#title' => $this->t('@title settings', ['@title' => $element['target_id']['#title']]),
|
||||
'#element_validate' => [[$this, 'validateOpenClose']],
|
||||
'#open' => ($items[$delta]->target_id) ? TRUE : FALSE,
|
||||
'#weight' => $weight++,
|
||||
];
|
||||
|
||||
$element['settings']['status'] = [
|
||||
'#type' => 'radios',
|
||||
'#title' => $this->t('Status'),
|
||||
'#options' => [
|
||||
WebformInterface::STATUS_OPEN => $this->t('Open'),
|
||||
WebformInterface::STATUS_CLOSED => $this->t('Closed'),
|
||||
WebformInterface::STATUS_SCHEDULED => $this->t('Scheduled'),
|
||||
],
|
||||
'#options_display' => 'side_by_side',
|
||||
'#default_value' => $items[$delta]->status,
|
||||
];
|
||||
|
||||
$element['settings']['scheduled'] = [
|
||||
'#type' => 'item',
|
||||
'#title' => $element['target_id']['#title'],
|
||||
'#title_display' => 'invisible',
|
||||
'#input' => FALSE,
|
||||
'#states' => [
|
||||
'visible' => [
|
||||
'input[name="' . $field_input_name . '[settings][status]"]' => ['value' => WebformInterface::STATUS_SCHEDULED],
|
||||
],
|
||||
],
|
||||
];
|
||||
$element['settings']['scheduled']['open'] = [
|
||||
'#type' => 'datetime',
|
||||
'#title' => $this->t('Open'),
|
||||
'#default_value' => $items[$delta]->open ? DrupalDateTime::createFromTimestamp(strtotime($items[$delta]->open)) : NULL,
|
||||
'#prefix' => '<div class="container-inline form-item">',
|
||||
'#suffix' => '</div>',
|
||||
'#help' => FALSE,
|
||||
'#description' => [
|
||||
'#type' => 'webform_help',
|
||||
'#help' => $this->t('If the open date/time is left blank, this form will immediately be opened.'),
|
||||
'#help_title' => $this->t('Open'),
|
||||
],
|
||||
];
|
||||
$element['settings']['scheduled']['close'] = [
|
||||
'#type' => 'datetime',
|
||||
'#title' => $this->t('Close'),
|
||||
'#default_value' => $items[$delta]->close ? DrupalDateTime::createFromTimestamp(strtotime($items[$delta]->close)) : NULL,
|
||||
'#prefix' => '<div class="container-inline form-item">',
|
||||
'#suffix' => '</div>',
|
||||
'#help' => FALSE,
|
||||
'#description' => [
|
||||
'#type' => 'webform_help',
|
||||
'#help' => $this->t('If the close date/time is left blank, this webform will never be closed.'),
|
||||
'#help_title' => $this->t('Close'),
|
||||
],
|
||||
];
|
||||
|
||||
if ($this->getSetting('default_data')) {
|
||||
/** @var \Drupal\webform\WebformTokenManagerInterface $token_manager */
|
||||
$token_manager = \Drupal::service('webform.token_manager');
|
||||
|
||||
$element['settings']['default_data'] = [
|
||||
'#type' => 'webform_codemirror',
|
||||
'#mode' => 'yaml',
|
||||
'#title' => $this->t('Default submission data (YAML)'),
|
||||
'#placeholder' => $this->t("Enter 'name': 'value' pairs…"),
|
||||
'#default_value' => $items[$delta]->default_data,
|
||||
'#webform_element' => TRUE,
|
||||
'#description' => [
|
||||
'content' => ['#markup' => $this->t('Enter submission data as name and value pairs as <a href=":href">YAML</a> which will be used to prepopulate the selected webform.', [':href' => 'https://en.wikipedia.org/wiki/YAML']), '#suffix' => ' '],
|
||||
'token' => $token_manager->buildTreeLink(),
|
||||
],
|
||||
'#more_title' => $this->t('Example'),
|
||||
'#more' => [
|
||||
'#theme' => 'webform_codemirror',
|
||||
'#type' => 'yaml',
|
||||
'#code' => "# This is an example of a comment.
|
||||
element_key: 'some value'
|
||||
|
||||
# The below example uses a token to get the current node's title.
|
||||
# Add ':clear' to the end token to return an empty value when the token is missing.
|
||||
title: '[webform_submission:node:title:clear]'
|
||||
# The below example uses a token to get a field value from the current node.
|
||||
full_name: '[webform_submission:node:field_full_name:clear]",
|
||||
],
|
||||
];
|
||||
$element['settings']['token_tree_link'] = $token_manager->buildTreeElement();
|
||||
}
|
||||
|
||||
return $element;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function massageFormValues(array $values, array $form, FormStateInterface $form_state) {
|
||||
parent::massageFormValues($values, $form, $form_state);
|
||||
|
||||
// Massage open/close dates.
|
||||
// @see \Drupal\webform\WebformEntitySettingsForm::save
|
||||
// @see \Drupal\datetime\Plugin\Field\FieldWidget\DateTimeWidgetBase::massageFormValues
|
||||
foreach ($values as &$item) {
|
||||
$item += $item['settings'];
|
||||
unset($item['settings']);
|
||||
|
||||
if ($item['status'] === WebformInterface::STATUS_SCHEDULED) {
|
||||
$states = ['open', 'close'];
|
||||
foreach ($states as $state) {
|
||||
if (!empty($item['scheduled'][$state]) && $item['scheduled'][$state] instanceof DrupalDateTime) {
|
||||
$item[$state] = WebformDateHelper::formatStorage($item['scheduled'][$state]);
|
||||
}
|
||||
else {
|
||||
$item[$state] = '';
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
$item['open'] = '';
|
||||
$item['close'] = '';
|
||||
}
|
||||
unset($item['scheduled']);
|
||||
}
|
||||
return $values;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate callback to ensure that the open date <= the close date.
|
||||
*
|
||||
* @param array $element
|
||||
* An associative array containing the properties and children of the
|
||||
* generic form element.
|
||||
* @param \Drupal\Core\Form\FormStateInterface $form_state
|
||||
* The current state of the form.
|
||||
* @param array $complete_form
|
||||
* The complete form structure.
|
||||
*
|
||||
* @see \Drupal\webform\WebformEntitySettingsForm::validateForm
|
||||
* @see \Drupal\datetime_range\Plugin\Field\FieldWidget\DateRangeWidgetBase::validateOpenClose
|
||||
*/
|
||||
public function validateOpenClose(array &$element, FormStateInterface $form_state, array &$complete_form) {
|
||||
$status = $element['status']['#value'];
|
||||
if ($status === WebformInterface::STATUS_SCHEDULED) {
|
||||
$open_date = $element['scheduled']['open']['#value']['object'];
|
||||
$close_date = $element['scheduled']['close']['#value']['object'];
|
||||
|
||||
// Require open or close dates.
|
||||
if (empty($open_date) && empty($close_date)) {
|
||||
$form_state->setError($element['scheduled']['open'], $this->t('Please enter an open or close date'));
|
||||
$form_state->setError($element['scheduled']['close'], $this->t('Please enter an open or close date'));
|
||||
}
|
||||
|
||||
// Make sure open date is not after close date.
|
||||
if ($open_date instanceof DrupalDateTime && $close_date instanceof DrupalDateTime) {
|
||||
if ($open_date->getTimestamp() !== $close_date->getTimestamp()) {
|
||||
$interval = $open_date->diff($close_date);
|
||||
if ($interval->invert === 1) {
|
||||
$form_state->setError($element['scheduled']['open'], $this->t('The @title close date cannot be before the open date', ['@title' => $element['#title']]));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -2,10 +2,12 @@
|
|||
|
||||
namespace Drupal\webform\Plugin\Field\FieldWidget;
|
||||
|
||||
use Drupal\Core\Entity\FieldableEntityInterface;
|
||||
use Drupal\Core\Field\FieldItemListInterface;
|
||||
use Drupal\Core\Form\FormStateInterface;
|
||||
use Drupal\webform\Entity\Webform;
|
||||
use Drupal\webform\WebformInterface;
|
||||
use Drupal\Core\Field\Plugin\Field\FieldWidget\OptionsWidgetBase;
|
||||
|
||||
/**
|
||||
* Plugin implementation of the 'webform_entity_reference_select' widget.
|
||||
|
@ -19,85 +21,50 @@ use Drupal\webform\WebformInterface;
|
|||
* }
|
||||
* )
|
||||
*
|
||||
* @see \Drupal\webform\Plugin\Field\FieldWidget\WebformEntityReferenceAutocompleteWidget
|
||||
* @see \Drupal\Core\Field\Plugin\Field\FieldWidget\EntityReferenceAutocompleteWidget
|
||||
* @see \Drupal\Core\Field\Plugin\Field\FieldWidget\OptionsSelectWidget
|
||||
* @see \Drupal\Core\Field\Plugin\Field\FieldWidget\OptionsWidgetBase
|
||||
*/
|
||||
class WebformEntityReferenceSelectWidget extends WebformEntityReferenceAutocompleteWidget {
|
||||
class WebformEntityReferenceSelectWidget extends OptionsWidgetBase {
|
||||
|
||||
use WebformEntityReferenceWidgetTrait;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function defaultSettings() {
|
||||
return [
|
||||
'default_data' => TRUE,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function settingsForm(array $form, FormStateInterface $form_state) {
|
||||
$element = [];
|
||||
$element['default_data'] = [
|
||||
'#type' => 'checkbox',
|
||||
'#title' => t('Enable default submission data (YAML)'),
|
||||
'#description' => t('If checked, site builders will be able to define default submission data (YAML)'),
|
||||
'#default_value' => $this->getSetting('default_data'),
|
||||
];
|
||||
return $element;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function settingsSummary() {
|
||||
$summary = [];
|
||||
$summary[] = t('Default submission data: @default_data', ['@default_data' => $this->getSetting('default_data') ? $this->t('Yes') : $this->t('No')]);
|
||||
return $summary;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function formElement(FieldItemListInterface $items, $delta, array $element, array &$form, FormStateInterface $form_state) {
|
||||
$element = parent::formElement($items, $delta, $element, $form, $form_state);
|
||||
|
||||
// Convert 'entity_autocomplete' to 'webform_entity_select' element.
|
||||
$element['target_id']['#type'] = 'webform_entity_select';
|
||||
|
||||
/** @var \Drupal\webform\WebformEntityStorageInterface $webform_storage */
|
||||
$webform_storage = \Drupal::service('entity_type.manager')->getStorage('webform');
|
||||
$element['target_id']['#options'] = $webform_storage->getOptions(FALSE);
|
||||
|
||||
// Set empty option.
|
||||
if (empty($element['#required'])) {
|
||||
$element['target_id']['#empty_option'] = $this->t('- Select -');
|
||||
$element['target_id']['#empty_value'] = '';
|
||||
}
|
||||
|
||||
public function getTargetIdElement(FieldItemListInterface $items, $delta, array $element, array &$form, FormStateInterface $form_state) {
|
||||
// Get default value (webform ID).
|
||||
$referenced_entities = $items->referencedEntities();
|
||||
$default_value = isset($referenced_entities[$delta]) ? $referenced_entities[$delta] : NULL;
|
||||
// Convert default_value's Webform to a simple entity_id.
|
||||
if (!empty($element['target_id']['#default_value']) && $element['target_id']['#default_value'] instanceof WebformInterface) {
|
||||
$element['target_id']['#default_value'] = $element['target_id']['#default_value']->id();
|
||||
if ($default_value instanceof WebformInterface) {
|
||||
$default_value = $default_value->id();
|
||||
}
|
||||
|
||||
// Get options grouped by category.
|
||||
$options = $this->getOptions($items->getEntity());
|
||||
// Make sure if an archived webform is the #default_value always include
|
||||
// it as an option.
|
||||
if (!empty($element['target_id']['#default_value'])) {
|
||||
$webform = ($element['target_id']['#default_value'] instanceof WebformInterface) ? $element['target_id']['#default_value'] : Webform::load($element['target_id']['#default_value']);
|
||||
if ($webform && $webform->isArchived()) {
|
||||
$element['target_id']['#options'][(string) t('Archived')][$webform->id()] = $webform->label();
|
||||
if ($default_value && $webform = Webform::load($default_value)) {
|
||||
if ($webform->isArchived()) {
|
||||
$options[(string) t('Archived')][$webform->id()] = $webform->label();
|
||||
}
|
||||
}
|
||||
|
||||
// Remove properties that are not applicable.
|
||||
unset($element['target_id']['#size']);
|
||||
unset($element['target_id']['#maxlength']);
|
||||
unset($element['target_id']['#placeholder']);
|
||||
$target_element = [
|
||||
'#type' => 'webform_entity_select',
|
||||
'#options' => $options,
|
||||
'#default_value' => $default_value,
|
||||
];
|
||||
|
||||
$element['#element_validate'] = [[get_class($this), 'validateWebformEntityReferenceSelectWidget']];
|
||||
// Set empty option.
|
||||
if (empty($element['#required'])) {
|
||||
$target_element['#empty_option'] = $this->t('- Select -');
|
||||
$target_element['#empty_value'] = '';
|
||||
}
|
||||
|
||||
return $element;
|
||||
// Set validation callback.
|
||||
$target_element['#element_validate'] = [[get_class($this), 'validateWebformEntityReferenceSelectWidget']];
|
||||
|
||||
return $target_element;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -107,8 +74,41 @@ class WebformEntityReferenceSelectWidget extends WebformEntityReferenceAutocompl
|
|||
// Below prevents the below error.
|
||||
// Fatal error: Call to a member function uuid() on a non-object in
|
||||
// core/lib/Drupal/Core/Field/EntityReferenceFieldItemList.php.
|
||||
$value = (!empty($element['target_id']['#value'])) ? $element['target_id']['#value'] : NULL;
|
||||
$form_state->setValueForElement($element['target_id'], $value);
|
||||
$value = (!empty($element['#value'])) ? $element['#value'] : NULL;
|
||||
$form_state->setValueForElement($element, $value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the array of options for the widget.
|
||||
*
|
||||
* @param \Drupal\Core\Entity\FieldableEntityInterface $entity
|
||||
* The entity for which to return options.
|
||||
*
|
||||
* @return array
|
||||
* The array of options for the widget.
|
||||
*/
|
||||
protected function getOptions(FieldableEntityInterface $entity) {
|
||||
if (!isset($this->options)) {
|
||||
// Limit the settable options for the current user account.
|
||||
// Note: All active webforms are returned and grouped by category.
|
||||
// @see \Drupal\webform\Plugin\Field\FieldType\WebformEntityReferenceItem::getSettableOptions
|
||||
// @see \Drupal\webform\WebformEntityStorageInterface::getOptions
|
||||
$options = $this->fieldDefinition
|
||||
->getFieldStorageDefinition()
|
||||
->getOptionsProvider($this->column, $entity)
|
||||
->getSettableOptions(\Drupal::currentUser());
|
||||
|
||||
$module_handler = \Drupal::moduleHandler();
|
||||
$context = [
|
||||
'fieldDefinition' => $this->fieldDefinition,
|
||||
'entity' => $entity,
|
||||
];
|
||||
$module_handler->alter('options_list', $options, $context);
|
||||
|
||||
array_walk_recursive($options, [$this, 'sanitizeLabel']);
|
||||
$this->options = $options;
|
||||
}
|
||||
return $this->options;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,260 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\webform\Plugin\Field\FieldWidget;
|
||||
|
||||
use Drupal\Core\Datetime\DrupalDateTime;
|
||||
use Drupal\Core\Field\FieldItemListInterface;
|
||||
use Drupal\Core\Form\FormStateInterface;
|
||||
use Drupal\webform\Utility\WebformDateHelper;
|
||||
use Drupal\webform\WebformInterface;
|
||||
|
||||
/**
|
||||
* Trait for webform entity reference and autocomplete widget.
|
||||
*/
|
||||
trait WebformEntityReferenceWidgetTrait {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function defaultSettings() {
|
||||
return [
|
||||
'default_data' => TRUE,
|
||||
] + parent::defaultSettings();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function settingsForm(array $form, FormStateInterface $form_state) {
|
||||
$element = parent::settingsForm($form, $form_state);
|
||||
$element['default_data'] = [
|
||||
'#type' => 'checkbox',
|
||||
'#title' => t('Enable default submission data (YAML)'),
|
||||
'#description' => t('If checked, site builders will be able to define default submission data (YAML)'),
|
||||
'#default_value' => $this->getSetting('default_data'),
|
||||
];
|
||||
return $element;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function settingsSummary() {
|
||||
$summary = parent::settingsSummary();
|
||||
$summary[] = t('Default submission data: @default_data', ['@default_data' => $this->getSetting('default_data') ? $this->t('Yes') : $this->t('No')]);
|
||||
return $summary;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the target id element form for a single webform field widget.
|
||||
*
|
||||
* @param \Drupal\Core\Field\FieldItemListInterface $items
|
||||
* Array of default values for this field.
|
||||
* @param int $delta
|
||||
* The order of this item in the array of sub-elements (0, 1, 2, etc.).
|
||||
* @param array $element
|
||||
* A form element array containing basic properties for the widget.
|
||||
* @param array $form
|
||||
* The form structure where widgets are being attached to. This might be a
|
||||
* full form structure, or a sub-element of a larger form.
|
||||
* @param \Drupal\Core\Form\FormStateInterface $form_state
|
||||
* The current state of the form.
|
||||
*
|
||||
* @return array
|
||||
* The form elements for a single widget for this field.
|
||||
*/
|
||||
abstract protected function getTargetIdElement(FieldItemListInterface $items, $delta, array $element, array &$form, FormStateInterface $form_state);
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function formElement(FieldItemListInterface $items, $delta, array $element, array &$form, FormStateInterface $form_state) {
|
||||
// Set item default status to open.
|
||||
if (!isset($items[$delta]->status)) {
|
||||
$items[$delta]->status = WebformInterface::STATUS_OPEN;
|
||||
}
|
||||
|
||||
// Get field name.
|
||||
$field_name = $items->getName();
|
||||
|
||||
// Get field input name from field parents, field name, and the delta.
|
||||
$field_parents = array_merge($element['#field_parents'], [$field_name, $delta]);
|
||||
$field_input_name = (array_shift($field_parents)) . ('[' . implode('][', $field_parents) . ']');
|
||||
|
||||
// Get target ID element.
|
||||
$target_id_element = $this->getTargetIdElement($items, $delta, $element, $form, $form_state);
|
||||
|
||||
// Merge target ID and default element and set default #weight.
|
||||
// @see \Drupal\Core\Field\Plugin\Field\FieldWidget\EntityReferenceAutocompleteWidget::formElement
|
||||
$element = [
|
||||
'target_id' => $target_id_element + $element + ['#weight' => 0],
|
||||
];
|
||||
|
||||
// Get weight.
|
||||
$weight = $element['target_id']['#weight'];
|
||||
|
||||
$element['settings'] = [
|
||||
'#type' => 'details',
|
||||
'#title' => $this->t('@title settings', ['@title' => $element['target_id']['#title']]),
|
||||
'#element_validate' => [[$this, 'validateOpenClose']],
|
||||
'#open' => ($items[$delta]->target_id) ? TRUE : FALSE,
|
||||
'#weight' => $weight++,
|
||||
];
|
||||
|
||||
$element['settings']['status'] = [
|
||||
'#type' => 'radios',
|
||||
'#title' => $this->t('Status'),
|
||||
'#options' => [
|
||||
WebformInterface::STATUS_OPEN => $this->t('Open'),
|
||||
WebformInterface::STATUS_CLOSED => $this->t('Closed'),
|
||||
WebformInterface::STATUS_SCHEDULED => $this->t('Scheduled'),
|
||||
],
|
||||
'#options_display' => 'side_by_side',
|
||||
'#default_value' => $items[$delta]->status,
|
||||
];
|
||||
|
||||
$element['settings']['scheduled'] = [
|
||||
'#type' => 'item',
|
||||
'#title' => $element['target_id']['#title'],
|
||||
'#title_display' => 'invisible',
|
||||
'#input' => FALSE,
|
||||
'#states' => [
|
||||
'visible' => [
|
||||
'input[name="' . $field_input_name . '[settings][status]"]' => ['value' => WebformInterface::STATUS_SCHEDULED],
|
||||
],
|
||||
],
|
||||
];
|
||||
$element['settings']['scheduled']['open'] = [
|
||||
'#type' => 'datetime',
|
||||
'#title' => $this->t('Open'),
|
||||
'#default_value' => $items[$delta]->open ? DrupalDateTime::createFromTimestamp(strtotime($items[$delta]->open)) : NULL,
|
||||
'#prefix' => '<div class="container-inline form-item">',
|
||||
'#suffix' => '</div>',
|
||||
'#help' => FALSE,
|
||||
'#description' => [
|
||||
'#type' => 'webform_help',
|
||||
'#help' => $this->t('If the open date/time is left blank, this form will immediately be opened.'),
|
||||
'#help_title' => $this->t('Open'),
|
||||
],
|
||||
];
|
||||
$element['settings']['scheduled']['close'] = [
|
||||
'#type' => 'datetime',
|
||||
'#title' => $this->t('Close'),
|
||||
'#default_value' => $items[$delta]->close ? DrupalDateTime::createFromTimestamp(strtotime($items[$delta]->close)) : NULL,
|
||||
'#prefix' => '<div class="container-inline form-item">',
|
||||
'#suffix' => '</div>',
|
||||
'#help' => FALSE,
|
||||
'#description' => [
|
||||
'#type' => 'webform_help',
|
||||
'#help' => $this->t('If the close date/time is left blank, this webform will never be closed.'),
|
||||
'#help_title' => $this->t('Close'),
|
||||
],
|
||||
];
|
||||
|
||||
if ($this->getSetting('default_data')) {
|
||||
/** @var \Drupal\webform\WebformTokenManagerInterface $token_manager */
|
||||
$token_manager = \Drupal::service('webform.token_manager');
|
||||
|
||||
$element['settings']['default_data'] = [
|
||||
'#type' => 'webform_codemirror',
|
||||
'#mode' => 'yaml',
|
||||
'#title' => $this->t('Default submission data (YAML)'),
|
||||
'#placeholder' => $this->t("Enter 'name': 'value' pairs…"),
|
||||
'#default_value' => $items[$delta]->default_data,
|
||||
'#webform_element' => TRUE,
|
||||
'#description' => [
|
||||
'content' => ['#markup' => $this->t('Enter submission data as name and value pairs as <a href=":href">YAML</a> which will be used to prepopulate the selected webform.', [':href' => 'https://en.wikipedia.org/wiki/YAML']), '#suffix' => ' '],
|
||||
'token' => $token_manager->buildTreeLink(),
|
||||
],
|
||||
'#more_title' => $this->t('Example'),
|
||||
'#more' => [
|
||||
'#theme' => 'webform_codemirror',
|
||||
'#type' => 'yaml',
|
||||
'#code' => "# This is an example of a comment.
|
||||
element_key: 'some value'
|
||||
|
||||
# The below example uses a token to get the current node's title.
|
||||
# Add ':clear' to the end token to return an empty value when the token is missing.
|
||||
title: '[webform_submission:node:title:clear]'
|
||||
# The below example uses a token to get a field value from the current node.
|
||||
full_name: '[webform_submission:node:field_full_name:clear]",
|
||||
],
|
||||
];
|
||||
$element['settings']['token_tree_link'] = $token_manager->buildTreeElement();
|
||||
}
|
||||
|
||||
return $element;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function massageFormValues(array $values, array $form, FormStateInterface $form_state) {
|
||||
parent::massageFormValues($values, $form, $form_state);
|
||||
|
||||
// Massage open/close dates.
|
||||
// @see \Drupal\webform\WebformEntitySettingsForm::save
|
||||
// @see \Drupal\datetime\Plugin\Field\FieldWidget\DateTimeWidgetBase::massageFormValues
|
||||
foreach ($values as &$item) {
|
||||
$item += $item['settings'];
|
||||
unset($item['settings']);
|
||||
|
||||
if ($item['status'] === WebformInterface::STATUS_SCHEDULED) {
|
||||
$states = ['open', 'close'];
|
||||
foreach ($states as $state) {
|
||||
if (!empty($item['scheduled'][$state]) && $item['scheduled'][$state] instanceof DrupalDateTime) {
|
||||
$item[$state] = WebformDateHelper::formatStorage($item['scheduled'][$state]);
|
||||
}
|
||||
else {
|
||||
$item[$state] = '';
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
$item['open'] = '';
|
||||
$item['close'] = '';
|
||||
}
|
||||
unset($item['scheduled']);
|
||||
}
|
||||
return $values;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate callback to ensure that the open date <= the close date.
|
||||
*
|
||||
* @param array $element
|
||||
* An associative array containing the properties and children of the
|
||||
* generic form element.
|
||||
* @param \Drupal\Core\Form\FormStateInterface $form_state
|
||||
* The current state of the form.
|
||||
* @param array $complete_form
|
||||
* The complete form structure.
|
||||
*
|
||||
* @see \Drupal\webform\WebformEntitySettingsForm::validateForm
|
||||
* @see \Drupal\datetime_range\Plugin\Field\FieldWidget\DateRangeWidgetBase::validateOpenClose
|
||||
*/
|
||||
public function validateOpenClose(array &$element, FormStateInterface $form_state, array &$complete_form) {
|
||||
$status = $element['status']['#value'];
|
||||
if ($status === WebformInterface::STATUS_SCHEDULED) {
|
||||
$open_date = $element['scheduled']['open']['#value']['object'];
|
||||
$close_date = $element['scheduled']['close']['#value']['object'];
|
||||
|
||||
// Require open or close dates.
|
||||
if (empty($open_date) && empty($close_date)) {
|
||||
$form_state->setError($element['scheduled']['open'], $this->t('Please enter an open or close date'));
|
||||
$form_state->setError($element['scheduled']['close'], $this->t('Please enter an open or close date'));
|
||||
}
|
||||
|
||||
// Make sure open date is not after close date.
|
||||
if ($open_date instanceof DrupalDateTime && $close_date instanceof DrupalDateTime) {
|
||||
if ($open_date->getTimestamp() !== $close_date->getTimestamp()) {
|
||||
$interval = $open_date->diff($close_date);
|
||||
if ($interval->invert === 1) {
|
||||
$form_state->setError($element['scheduled']['open'], $this->t('The @title close date cannot be before the open date', ['@title' => $element['#title']]));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -89,6 +89,13 @@ class Checkboxes extends OptionsBase {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getElementSelectorSourceValues(array $element) {
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
|
|
|
@ -34,6 +34,7 @@ class Container extends ContainerBase {
|
|||
'format' => $this->getItemDefaultFormat(),
|
||||
'format_html' => '',
|
||||
'format_text' => '',
|
||||
'format_attributes' => [],
|
||||
];
|
||||
}
|
||||
|
||||
|
|
|
@ -30,6 +30,7 @@ abstract class ContainerBase extends WebformElementBase {
|
|||
'format' => $this->getItemDefaultFormat(),
|
||||
'format_html' => '',
|
||||
'format_text' => '',
|
||||
'format_attributes' => [],
|
||||
] + $this->getDefaultBaseProperties();
|
||||
}
|
||||
|
||||
|
@ -128,35 +129,34 @@ abstract class ContainerBase extends WebformElementBase {
|
|||
$format = 'header';
|
||||
}
|
||||
|
||||
// Build format attributes.
|
||||
$attributes = (isset($element['#format_attributes'])) ? $element['#format_attributes'] : [];
|
||||
$attributes += ['class' => []];
|
||||
|
||||
switch ($format) {
|
||||
case 'details':
|
||||
case 'details-closed':
|
||||
$attributes['data-webform-element-id'] = $element['#webform_id'];
|
||||
$attributes['class'][] = 'webform-container';
|
||||
$attributes['class'][] = 'webform-container-type-details';
|
||||
return [
|
||||
'#type' => 'details',
|
||||
'#title' => $element['#title'],
|
||||
'#id' => $element['#webform_id'],
|
||||
'#open' => ($format === 'details-closed') ? FALSE : TRUE,
|
||||
'#attributes' => [
|
||||
'data-webform-element-id' => $element['#webform_id'],
|
||||
'class' => [
|
||||
'webform-container',
|
||||
'webform-container-type-details',
|
||||
],
|
||||
],
|
||||
'#attributes' => $attributes,
|
||||
'#children' => $children,
|
||||
];
|
||||
|
||||
case 'fieldset':
|
||||
$attributes['class'][] = 'webform-container';
|
||||
$attributes['class'][] = 'webform-container-type-fieldset';
|
||||
|
||||
return [
|
||||
'#type' => 'fieldset',
|
||||
'#title' => $element['#title'],
|
||||
'#id' => $element['#webform_id'],
|
||||
'#attributes' => [
|
||||
'class' => [
|
||||
'webform-container',
|
||||
'webform-container-type-fieldset',
|
||||
],
|
||||
],
|
||||
'#attributes' => $attributes,
|
||||
'#children' => $children,
|
||||
];
|
||||
|
||||
|
@ -167,6 +167,7 @@ abstract class ContainerBase extends WebformElementBase {
|
|||
'#id' => $element['#webform_id'],
|
||||
'#title' => $element['#title'],
|
||||
'#title_tag' => \Drupal::config('webform.settings')->get('element.default_section_title_tag'),
|
||||
'#attributes' => $attributes,
|
||||
] + $children;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -35,6 +35,7 @@ class Date extends DateBase {
|
|||
return [
|
||||
// Date settings.
|
||||
'datepicker' => FALSE,
|
||||
'datepicker_button' => FALSE,
|
||||
'date_date_format' => $date_format,
|
||||
'step' => '',
|
||||
'size' => '',
|
||||
|
@ -59,8 +60,7 @@ class Date extends DateBase {
|
|||
// Prepare element after date format has been updated.
|
||||
parent::prepare($element, $webform_submission);
|
||||
|
||||
// Set the (input) type attribute to 'date' since #min and #max will
|
||||
// override the default attributes.
|
||||
// Set the (input) type attribute to 'date'.
|
||||
// @see \Drupal\Core\Render\Element\Date::getInfo
|
||||
$element['#attributes']['type'] = 'date';
|
||||
|
||||
|
@ -85,11 +85,11 @@ class Date extends DateBase {
|
|||
if (isset($element['#default_value'])) {
|
||||
if ($this->hasMultipleValues($element)) {
|
||||
foreach ($element['#default_value'] as $index => $default_value) {
|
||||
$element['#default_value'][$index] = date($element['#date_date_format'], strtotime($default_value));
|
||||
$element['#default_value'][$index] = static::formatDate($element['#date_date_format'], strtotime($default_value));
|
||||
}
|
||||
}
|
||||
else {
|
||||
$element['#default_value'] = date($element['#date_date_format'], strtotime($element['#default_value']));
|
||||
$element['#default_value'] = static::formatDate($element['#date_date_format'], strtotime($element['#default_value']));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -120,15 +120,26 @@ class Date extends DateBase {
|
|||
'#description' => $this->t('If checked, the HTML5 date element will be replaced with <a href="https://jqueryui.com/datepicker/">jQuery UI datepicker</a>'),
|
||||
'#return_value' => TRUE,
|
||||
];
|
||||
$form['date']['datepicker_button'] = [
|
||||
'#type' => 'checkbox',
|
||||
'#title' => $this->t('Show date picker button'),
|
||||
'#description' => $this->t('If checked, date picker will include a calendar button'),
|
||||
'#return_value' => TRUE,
|
||||
'#states' => [
|
||||
'visible' => [
|
||||
':input[name="properties[datepicker]"]' => ['checked' => TRUE],
|
||||
],
|
||||
],
|
||||
];
|
||||
$date_format = DateFormat::load('html_date')->getPattern();
|
||||
$form['date']['date_date_format'] = [
|
||||
'#type' => 'webform_select_other',
|
||||
'#title' => $this->t('Date format'),
|
||||
'#options' => [
|
||||
$date_format => $this->t('HTML date - @format (@date)', ['@format' => $date_format, '@date' => date($date_format)]),
|
||||
'l, F j, Y' => $this->t('Long date - @format (@date)', ['@format' => 'l, F j, Y', '@date' => date('l, F j, Y')]),
|
||||
'D, m/d/Y' => $this->t('Medium date - @format (@date)', ['@format' => 'D, m/d/Y', '@date' => date('D, m/d/Y')]),
|
||||
'm/d/Y' => $this->t('Short date - @format (@date)', ['@format' => 'm/d/Y', '@date' => date('m/d/Y')]),
|
||||
$date_format => $this->t('HTML date - @format (@date)', ['@format' => $date_format, '@date' => static::formatDate($date_format)]),
|
||||
'l, F j, Y' => $this->t('Long date - @format (@date)', ['@format' => 'l, F j, Y', '@date' => static::formatDate('l, F j, Y')]),
|
||||
'D, m/d/Y' => $this->t('Medium date - @format (@date)', ['@format' => 'D, m/d/Y', '@date' => static::formatDate('D, m/d/Y')]),
|
||||
'm/d/Y' => $this->t('Short date - @format (@date)', ['@format' => 'm/d/Y', '@date' => static::formatDate('m/d/Y')]),
|
||||
],
|
||||
'#description' => $this->t("Date format is only applicable for browsers that do not have support for the HTML5 date element. Browsers that support the HTML5 date element will display the date using the user's preferred format."),
|
||||
'#other__option_label' => $this->t('Custom…'),
|
||||
|
|
|
@ -8,7 +8,9 @@ use Drupal\Core\Cache\CacheableMetadata;
|
|||
use Drupal\Core\Datetime\DrupalDateTime;
|
||||
use Drupal\Core\Datetime\Entity\DateFormat;
|
||||
use Drupal\Core\Form\FormStateInterface;
|
||||
use Drupal\webform\Element\WebformMessage as WebformMessageElement;
|
||||
use Drupal\webform\Plugin\WebformElementBase;
|
||||
use Drupal\webform\Utility\WebformDateHelper;
|
||||
use Drupal\webform\WebformSubmissionInterface;
|
||||
use Drupal\webform\WebformInterface;
|
||||
|
||||
|
@ -23,8 +25,8 @@ abstract class DateBase extends WebformElementBase {
|
|||
public function getDefaultProperties() {
|
||||
return [
|
||||
// Form validation.
|
||||
'min' => '',
|
||||
'max' => '',
|
||||
'date_date_min' => '',
|
||||
'date_date_max' => '',
|
||||
] + parent::getDefaultProperties() + $this->getDefaultMultipleProperties();
|
||||
}
|
||||
|
||||
|
@ -54,25 +56,34 @@ abstract class DateBase extends WebformElementBase {
|
|||
// Parse #default_value date input format.
|
||||
$this->parseInputFormat($element, '#default_value');
|
||||
|
||||
// Override min/max attributes.
|
||||
// Set date min/max attributes.
|
||||
// This overrides extra attributes set via Datetime::processDatetime.
|
||||
// @see \Drupal\Core\Datetime\Element\Datetime::processDatetime
|
||||
if (isset($element['#date_date_format'])) {
|
||||
if (!empty($element['#min'])) {
|
||||
$element['#attributes']['min'] = date($element['#date_date_format'], strtotime($element['#min']));
|
||||
$element['#attributes']['data-min-year'] = date('Y', strtotime($element['#min']));
|
||||
$date_min = $this->getElementProperty($element, 'date_date_min') ?: $this->getElementProperty($element,'date_min');
|
||||
if ($date_min) {
|
||||
$element['#attributes']['min'] = static::formatDate($element['#date_date_format'], strtotime($date_min));
|
||||
$element['#attributes']['data-min-year'] = static::formatDate('Y', strtotime($date_min));
|
||||
}
|
||||
if (!empty($element['#max'])) {
|
||||
$element['#attributes']['max'] = date($element['#date_date_format'], strtotime($element['#max']));
|
||||
$element['#attributes']['data-max-year'] = date('Y', strtotime($element['#max']));
|
||||
$date_max = $this->getElementProperty($element, 'date_date_max') ?: $this->getElementProperty($element,'date_max');
|
||||
if (!empty($date_max)) {
|
||||
$element['#attributes']['max'] = static::formatDate($element['#date_date_format'], strtotime($date_max));
|
||||
$element['#attributes']['data-max-year'] = static::formatDate('Y', strtotime($date_max));
|
||||
}
|
||||
}
|
||||
|
||||
$element['#element_validate'] = array_merge([[get_class($this), 'preValidateDate']], $element['#element_validate']);
|
||||
$element['#element_validate'][] = [get_class($this), 'validateDate'];
|
||||
|
||||
// Display datepicker button.
|
||||
if (!empty($element['#datepicker_button']) || !empty($element['#date_date_datepicker_button'])) {
|
||||
$element['#attributes']['data-datepicker-button'] = TRUE;
|
||||
$element['#attached']['drupalSettings']['webform']['datePicker']['buttonImage'] = base_path() . drupal_get_path('module', 'webform') . '/images/elements/date-calendar.png';
|
||||
}
|
||||
|
||||
// Set first day according to admin/config/regional/settings.
|
||||
$config = $this->configFactory->get('system.date');
|
||||
$element['#attached']['drupalSettings']['webform']['dateFirstDay'] = $config->get('first_day');
|
||||
|
||||
$cacheability = CacheableMetadata::createFromObject($config);
|
||||
$cacheability->applyTo($element);
|
||||
|
||||
|
@ -119,7 +130,7 @@ abstract class DateBase extends WebformElementBase {
|
|||
return \Drupal::service('date.formatter')->format($timestamp, $format);
|
||||
}
|
||||
else {
|
||||
return date($format, $timestamp);
|
||||
return static::formatDate($format, $timestamp);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -186,19 +197,53 @@ abstract class DateBase extends WebformElementBase {
|
|||
'#title' => $this->t('Date settings'),
|
||||
];
|
||||
|
||||
$form['date']['min'] = [
|
||||
// Date min/max validation.
|
||||
$form['date']['date_date_min'] = [
|
||||
'#type' => 'textfield',
|
||||
'#title' => $this->t('Date min'),
|
||||
'#title' => $this->t('Date minimum'),
|
||||
'#description' => $this->t('Specifies the minimum date.') . '<br /><br />' . $this->t('Accepts any date in any <a href="https://www.gnu.org/software/tar/manual/html_chapter/tar_7.html#Date-input-formats">GNU Date Input Format</a>. Strings such as today, +2 months, and Dec 9 2004 are all valid.'),
|
||||
'#weight' => 10,
|
||||
];
|
||||
$form['date']['max'] = [
|
||||
$form['date']['date_date_max'] = [
|
||||
'#type' => 'textfield',
|
||||
'#title' => $this->t('Date max'),
|
||||
'#title' => $this->t('Date maximum'),
|
||||
'#description' => $this->t('Specifies the maximum date.') . '<br /><br />' . $this->t('Accepts any date in any <a href="https://www.gnu.org/software/tar/manual/html_chapter/tar_7.html#Date-input-formats">GNU Date Input Format</a>. Strings such as today, +2 months, and Dec 9 2004 are all valid.'),
|
||||
'#weight' => 10,
|
||||
];
|
||||
|
||||
// Date/time min/max validation.
|
||||
if ($this->hasProperty('date_date_min')
|
||||
&& $this->hasProperty('date_time_min')
|
||||
&& $this->hasProperty('date_min')) {
|
||||
$form['validation']['date_min_max_message'] = [
|
||||
'#type' => 'webform_message',
|
||||
'#message_type' => 'warning',
|
||||
'#access' => TRUE,
|
||||
'#message_message' => $this->t("'Date/time' minimum or maximum should not be used with 'Date' or 'Time' specific minimum or maximum.") . '<br/>' .
|
||||
'<strong>' . $this->t('This can cause unexpected validation errors.') . '</strong>',
|
||||
'#message_close' => TRUE,
|
||||
'#message_storage' => WebformMessageElement::STORAGE_SESSION,
|
||||
'#states' => [
|
||||
'visible' => [
|
||||
[':input[name="properties[date_date_min]"]' => ['filled' => TRUE]],
|
||||
[':input[name="properties[date_date_max]"]' => ['filled' => TRUE]],
|
||||
[':input[name="properties[date_time_min]"]' => ['filled' => TRUE]],
|
||||
[':input[name="properties[date_time_max]"]' => ['filled' => TRUE]],
|
||||
],
|
||||
],
|
||||
];
|
||||
}
|
||||
$form['validation']['date_min'] = [
|
||||
'#type' => 'textfield',
|
||||
'#title' => $this->t('Date/time minimum'),
|
||||
'#description' => $this->t('Specifies the minimum date/time.') . '<br /><br />' . $this->t('Accepts any date in any <a href="https://www.gnu.org/software/tar/manual/html_chapter/tar_7.html#Date-input-formats">GNU Date/Time Input Format</a>. Strings such as today, +2 months, and Dec 9 2004 10:00 PM are all valid.'),
|
||||
];
|
||||
$form['validation']['date_max'] = [
|
||||
'#type' => 'textfield',
|
||||
'#title' => $this->t('Date/time maximum'),
|
||||
'#description' => $this->t('Specifies the maximum date/time.') . '<br /><br />' . $this->t('Accepts any date in any <a href="https://www.gnu.org/software/tar/manual/html_chapter/tar_7.html#Date-input-formats">GNU Date/Time Input Format</a>. Strings such as today, +2 months, and Dec 9 2004 10:00 PM are all valid.'),
|
||||
];
|
||||
|
||||
return $form;
|
||||
}
|
||||
|
||||
|
@ -213,12 +258,18 @@ abstract class DateBase extends WebformElementBase {
|
|||
$this->setGnuDateInputFormatError($form['properties']['default']['default_value'], $form_state);
|
||||
}
|
||||
|
||||
// Validate #min and #max GNU Date Input Format.
|
||||
$input_formats = ['min', 'max'];
|
||||
foreach ($input_formats as $input_format) {
|
||||
if (!$this->validateGnuDateInputFormat($properties, "#$input_format")) {
|
||||
$this->setGnuDateInputFormatError($form['properties']['date'][$input_format], $form_state);
|
||||
}
|
||||
// Validate #*_min and #*_max GNU Date Input Format.
|
||||
if (!$this->validateGnuDateInputFormat($properties, '#date_min')) {
|
||||
$this->setGnuDateInputFormatError($form['properties']['validation']['date_min'], $form_state);
|
||||
}
|
||||
if (!$this->validateGnuDateInputFormat($properties, '#date_max')) {
|
||||
$this->setGnuDateInputFormatError($form['properties']['validation']['date_max'], $form_state);
|
||||
}
|
||||
if (!$this->validateGnuDateInputFormat($properties, '#date_date_min')) {
|
||||
$this->setGnuDateInputFormatError($form['properties']['date']['date_date_min'], $form_state);
|
||||
}
|
||||
if (!$this->validateGnuDateInputFormat($properties, '#date_date_max')) {
|
||||
$this->setGnuDateInputFormatError($form['properties']['date']['date_date_max'], $form_state);
|
||||
}
|
||||
|
||||
parent::validateConfigurationForm($form, $form_state);
|
||||
|
@ -360,7 +411,7 @@ abstract class DateBase extends WebformElementBase {
|
|||
/**
|
||||
* Webform element validation handler for date elements.
|
||||
*
|
||||
* Note that #required is validated by _form_validate() already.
|
||||
* Note that #required is validated by _form_valistatic::formatDate() already.
|
||||
*
|
||||
* @see \Drupal\Core\Render\Element\Number::validateNumber
|
||||
*/
|
||||
|
@ -368,16 +419,15 @@ abstract class DateBase extends WebformElementBase {
|
|||
$value = $element['#value'];
|
||||
$name = empty($element['#title']) ? $element['#parents'][0] : $element['#title'];
|
||||
$date_date_format = (!empty($element['#date_date_format'])) ? $element['#date_date_format'] : DateFormat::load('html_date')->getPattern();
|
||||
$date_time_format = (!empty($element['#date_time_format'])) ? $element['#date_time_format'] : DateFormat::load('html_time')->getPattern();
|
||||
|
||||
// Convert DrupalDateTime array and object to ISO datetime.
|
||||
if (is_array($value)) {
|
||||
$value = ($value['object']) ? $value['object']->format(DateFormat::load('html_datetime')->getPattern()) : '';
|
||||
}
|
||||
elseif ($value) {
|
||||
// Ensure the input is valid date by creating a date object and comparing
|
||||
// formatted date object to the submitted date value.
|
||||
$datetime = date_create_from_format($date_date_format, $value);
|
||||
if ($datetime === FALSE || date_format($datetime, $date_date_format) != $value) {
|
||||
$datetime = WebformDateHelper::createFromFormat($date_date_format, $value);
|
||||
if ($datetime === FALSE || static::formatDate($date_date_format, $datetime->getTimestamp()) != $value) {
|
||||
$form_state->setError($element, t('%name must be a valid date.', ['%name' => $name]));
|
||||
$value = '';
|
||||
}
|
||||
|
@ -400,24 +450,46 @@ abstract class DateBase extends WebformElementBase {
|
|||
|
||||
$time = strtotime($value);
|
||||
|
||||
// Ensure that the input is greater than the #min property, if set.
|
||||
if (isset($element['#min'])) {
|
||||
$min = strtotime(date('Y-m-d', strtotime($element['#min'])));
|
||||
// Ensure that the input is greater than the #date_date_min property, if set.
|
||||
if (isset($element['#date_date_min'])) {
|
||||
$min = strtotime(static::formatDate('Y-m-d', strtotime($element['#date_date_min'])));
|
||||
if ($time < $min) {
|
||||
$form_state->setError($element, t('%name must be on or after %min.', [
|
||||
'%name' => $name,
|
||||
'%min' => date($date_date_format, $min),
|
||||
'%min' => static::formatDate($date_date_format, $min),
|
||||
]));
|
||||
}
|
||||
}
|
||||
|
||||
// Ensure that the input is less than the #max property, if set.
|
||||
if (isset($element['#max'])) {
|
||||
$max = strtotime(date('Y-m-d', strtotime($element['#max'])));
|
||||
// Ensure that the input is less than the #date_date_max property, if set.
|
||||
if (isset($element['#date_date_max'])) {
|
||||
$max = strtotime(static::formatDate('Y-m-d 23:59:59', strtotime($element['#date_date_max'])));
|
||||
if ($time > $max) {
|
||||
$form_state->setError($element, t('%name must be on or before %max.', [
|
||||
'%name' => $name,
|
||||
'%max' => date($date_date_format, $max),
|
||||
'%max' => static::formatDate($date_date_format, $max),
|
||||
]));
|
||||
}
|
||||
}
|
||||
|
||||
// Ensure that the input is greater than the #date_min property, if set.
|
||||
if (isset($element['#date_min'])) {
|
||||
$min = strtotime($element['#date_min']);
|
||||
if ($time < $min) {
|
||||
$form_state->setError($element, t('%name must be on or after %min.', [
|
||||
'%name' => $name,
|
||||
'%min' => static::formatDate($date_date_format, $min) . ' ' . static::formatDate($date_time_format, $min),
|
||||
]));
|
||||
}
|
||||
}
|
||||
|
||||
// Ensure that the input is less than the #date_max property, if set.
|
||||
if (isset($element['#date_max'])) {
|
||||
$max = strtotime($element['#date_max']);
|
||||
if ($time > $max) {
|
||||
$form_state->setError($element, t('%name must be on or before %max.', [
|
||||
'%name' => $name,
|
||||
'%max' => static::formatDate($date_date_format, $max) . ' ' . static::formatDate($date_time_format, $max),
|
||||
]));
|
||||
}
|
||||
}
|
||||
|
@ -432,10 +504,10 @@ abstract class DateBase extends WebformElementBase {
|
|||
list($min, $max) = static::datetimeRangeYears($element['#date_year_range']);
|
||||
}
|
||||
else {
|
||||
$min = !empty($element['#min']) ? strtotime($element['#min']) : strtotime('-10 years');
|
||||
$max = !empty($element['#max']) ? strtotime($element['#max']) : max($min, strtotime('+20 years') ?: PHP_INT_MAX);
|
||||
$min = !empty($element['#date_date_min']) ? strtotime($element['#date_date_min']) : strtotime('-10 years');
|
||||
$max = !empty($element['#date_date_max']) ? strtotime($element['#date_date_max']) : max($min, strtotime('+20 years') ?: PHP_INT_MAX);
|
||||
}
|
||||
return date($format, rand($min, $max));
|
||||
return static::formatDate($format, rand($min, $max));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -494,4 +566,21 @@ abstract class DateBase extends WebformElementBase {
|
|||
return [$min_year, $max_year];
|
||||
}
|
||||
|
||||
/**
|
||||
* Format custom date.
|
||||
*
|
||||
* @param string $custom_format
|
||||
* A PHP date format string suitable for input to date().
|
||||
* @param int $timestamp
|
||||
* (optional) A UNIX timestamp to format.
|
||||
*
|
||||
* @return string
|
||||
* Formatted date.
|
||||
*/
|
||||
protected static function formatDate($custom_format, $timestamp = NULL) {
|
||||
/** @var \Drupal\Core\Datetime\DateFormatterInterface $date_formatter */
|
||||
$date_formatter = \Drupal::service('date.formatter');
|
||||
return $date_formatter->format($timestamp ?: time(), 'custom', $custom_format);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -28,6 +28,8 @@ class DateList extends DateBase {
|
|||
*/
|
||||
public function getDefaultProperties() {
|
||||
return [
|
||||
'date_min' => '',
|
||||
'date_max' => '',
|
||||
// Date settings.
|
||||
'date_part_order' => [
|
||||
'year',
|
||||
|
@ -36,12 +38,11 @@ class DateList extends DateBase {
|
|||
'hour',
|
||||
'minute',
|
||||
],
|
||||
'date_text_parts' => [
|
||||
'year',
|
||||
],
|
||||
'date_text_parts' => [],
|
||||
'date_year_range' => '1900:2050',
|
||||
'date_year_range_reverse' => FALSE,
|
||||
'date_increment' => 1,
|
||||
'date_abbreviate' => TRUE,
|
||||
] + parent::getDefaultProperties();
|
||||
}
|
||||
|
||||
|
@ -51,6 +52,14 @@ class DateList extends DateBase {
|
|||
public function prepare(array &$element, WebformSubmissionInterface $webform_submission = NULL) {
|
||||
parent::prepare($element, $webform_submission);
|
||||
|
||||
// Remove month abbreviation.
|
||||
// @see \Drupal\Core\Datetime\Element\Datelist::processDatelist
|
||||
if (isset($element['#date_abbreviate']) && $element['#date_abbreviate'] === FALSE) {
|
||||
$element['#date_date_callbacks'][] = '_webform_datelist_date_date_callback';
|
||||
}
|
||||
|
||||
$element['#attached']['library'][] = 'webform/webform.element.datelist';
|
||||
|
||||
$element['#after_build'][] = [get_class($this), 'afterBuild'];
|
||||
}
|
||||
|
||||
|
@ -186,6 +195,13 @@ class DateList extends DateBase {
|
|||
'#size' => 4,
|
||||
'#weight' => 10,
|
||||
];
|
||||
$form['date']['date_abbreviate'] = [
|
||||
'#type' => 'checkbox',
|
||||
'#title' => $this->t('Abbreviate month'),
|
||||
'#description' => $this->t('If checked, month will be abbreviated to three letters.'),
|
||||
'#return_value' => TRUE,
|
||||
];
|
||||
|
||||
return $form;
|
||||
}
|
||||
|
||||
|
|
|
@ -41,13 +41,15 @@ class DateTime extends DateBase {
|
|||
}
|
||||
|
||||
return [
|
||||
'date_min' => '',
|
||||
'date_max' => '',
|
||||
// Date settings.
|
||||
'date_date_format' => $date_format,
|
||||
'date_date_datepicker_button' => TRUE,
|
||||
'date_date_element' => 'date',
|
||||
'date_year_range' => '1900:2050',
|
||||
'date_increment' => 1,
|
||||
// Time settings.
|
||||
'date_time_format' => $time_format,
|
||||
'date_timezone' => '',
|
||||
'date_time_element' => 'time',
|
||||
'date_time_min' => '',
|
||||
'date_time_max' => '',
|
||||
|
@ -76,12 +78,23 @@ class DateTime extends DateBase {
|
|||
unset($element['date_date_format']);
|
||||
}
|
||||
|
||||
// Set date year range.
|
||||
$element += ['#date_year_range' => ''];
|
||||
if (empty($element['#date_year_range'])) {
|
||||
$date_min = $this->getElementProperty($element,'date_date_min') ?: $this->getElementProperty($element,'date_min');
|
||||
$min_year = ($date_min) ? static::formatDate('Y', strtotime($date_min)) : '1900';
|
||||
$date_max = $this->getElementProperty($element,'date_date_max') ?: $this->getElementProperty($element,'date_max');
|
||||
$max_year = ($date_max) ? static::formatDate('Y', strtotime($date_max)) : '2050';
|
||||
$element['#date_year_range'] = "$min_year:$max_year";
|
||||
}
|
||||
|
||||
// Set date format.
|
||||
if (!isset($element['#date_date_format'])) {
|
||||
$element['#date_date_format'] = $this->getDefaultProperty('date_date_format');
|
||||
}
|
||||
|
||||
$element['#date_date_callbacks'][] = '_webform_datetime_datepicker';
|
||||
// Add date callback.
|
||||
$element['#date_date_callbacks'][] = '_webform_datetime_date';
|
||||
|
||||
/* Time */
|
||||
|
||||
|
@ -90,13 +103,11 @@ class DateTime extends DateBase {
|
|||
$element['#date_time_format'] = $this->getDefaultProperty('date_time_format');
|
||||
}
|
||||
|
||||
// Add timepicker callback.
|
||||
$element['#date_time_callbacks'][] = '_webform_datetime_timepicker';
|
||||
// Add time callback.
|
||||
$element['#date_time_callbacks'][] = '_webform_datetime_time';
|
||||
|
||||
// Prepare element after date/time formats have been updated.
|
||||
parent::prepare($element, $webform_submission);
|
||||
|
||||
$element['#after_build'][] = [get_class($this), 'afterBuildDateTime'];
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -150,6 +161,18 @@ class DateTime extends DateBase {
|
|||
'none' => $this->t('None - Do not display a date element'),
|
||||
],
|
||||
];
|
||||
$form['date']['date_date_datepicker_button'] = [
|
||||
'#type' => 'checkbox',
|
||||
'#title' => $this->t('Show date picker button'),
|
||||
'#description' => $this->t('If checked, date picker will include a calendar button'),
|
||||
'#return_value' => TRUE,
|
||||
'#states' => [
|
||||
'visible' => [
|
||||
[':input[name="properties[date_date_element]"]' => ['value' => 'datepicker']],
|
||||
],
|
||||
],
|
||||
|
||||
];
|
||||
$form['date']['date_date_element_datetime_warning'] = [
|
||||
'#type' => 'webform_message',
|
||||
'#message_type' => 'warning',
|
||||
|
@ -179,10 +202,10 @@ class DateTime extends DateBase {
|
|||
'#type' => 'webform_select_other',
|
||||
'#title' => $this->t('Date format'),
|
||||
'#options' => [
|
||||
$date_format => $this->t('HTML date - @format (@date)', ['@format' => $date_format, '@date' => date($date_format)]),
|
||||
'l, F j, Y' => $this->t('Long date - @format (@date)', ['@format' => 'l, F j, Y', '@date' => date('l, F j, Y')]),
|
||||
'D, m/d/Y' => $this->t('Medium date - @format (@date)', ['@format' => 'D, m/d/Y', '@date' => date('D, m/d/Y')]),
|
||||
'm/d/Y' => $this->t('Short date - @format (@date)', ['@format' => 'm/d/Y', '@date' => date('m/d/Y')]),
|
||||
$date_format => $this->t('HTML date - @format (@date)', ['@format' => $date_format, '@date' => static::formatDate($date_format)]),
|
||||
'l, F j, Y' => $this->t('Long date - @format (@date)', ['@format' => 'l, F j, Y', '@date' => static::formatDate('l, F j, Y')]),
|
||||
'D, m/d/Y' => $this->t('Medium date - @format (@date)', ['@format' => 'D, m/d/Y', '@date' => static::formatDate('D, m/d/Y')]),
|
||||
'm/d/Y' => $this->t('Short date - @format (@date)', ['@format' => 'm/d/Y', '@date' => static::formatDate('m/d/Y')]),
|
||||
],
|
||||
'#other__option_label' => $this->t('Custom…'),
|
||||
'#other__placeholder' => $this->t('Custom date format…'),
|
||||
|
@ -195,15 +218,6 @@ class DateTime extends DateBase {
|
|||
],
|
||||
],
|
||||
];
|
||||
$form['date']['date_timezone'] = [
|
||||
'#type' => 'select',
|
||||
'#title' => $this->t('Date timezone override'),
|
||||
'#options' => system_time_zones(TRUE),
|
||||
'#description' => $this->t('Generally this should be left empty and it will be set correctly for the user using the webform.') . ' ' .
|
||||
$this->t('Useful if the default value is empty to designate a desired timezone for dates created in webform processing.') . ' ' .
|
||||
$this->t('If a default date is provided, this value will be ignored, the timezone in the default date takes precedence.') . ' ' .
|
||||
$this->t('Defaults to the value returned by drupal_get_user_timezone().'),
|
||||
];
|
||||
$form['date']['date_year_range'] = [
|
||||
'#type' => 'textfield',
|
||||
'#title' => $this->t('Date year range'),
|
||||
|
@ -218,23 +232,6 @@ class DateTime extends DateBase {
|
|||
],
|
||||
],
|
||||
];
|
||||
$form['date']['date_increment'] = [
|
||||
'#type' => 'number',
|
||||
'#title' => $this->t('Date increment'),
|
||||
'#description' => $this->t("The increment to use for minutes and seconds, i.e. '15' would show only :00, :15, :30 and :45. Used for HTML5 step values and jQueryUI (fallback) datepicker settings. Defaults to 1 to show every minute."),
|
||||
'#min' => 1,
|
||||
'#attributes' => ['data-webform-states-no-clear' => TRUE],
|
||||
'#states' => [
|
||||
'invisible' => [
|
||||
[':input[name="properties[date_date_element]"]' => ['value' => 'datetime']],
|
||||
'xor',
|
||||
[':input[name="properties[date_date_element]"]' => ['value' => 'datetime-local']],
|
||||
'xor',
|
||||
[':input[name="properties[date_time_element]"]' => ['value' => 'none']],
|
||||
],
|
||||
],
|
||||
'#weight' => 10,
|
||||
];
|
||||
|
||||
// Time.
|
||||
$form['time'] = [
|
||||
|
@ -263,10 +260,10 @@ class DateTime extends DateBase {
|
|||
'#title' => $this->t('Time format'),
|
||||
'#description' => $this->t("Time format is only applicable for browsers that do not have support for the HTML5 time element. Browsers that support the HTML5 time element will display the time using the user's preferred format."),
|
||||
'#options' => [
|
||||
'H:i:s' => $this->t('24 hour with seconds - @format (@time)', ['@format' => 'H:i:s', '@time' => date('H:i:s')]),
|
||||
'H:i' => $this->t('24 hour - @format (@time)', ['@format' => 'H:i', '@time' => date('H:i')]),
|
||||
'g:i:s A' => $this->t('12 hour with seconds - @format (@time)', ['@format' => 'g:i:s A', '@time' => date('g:i:s A')]),
|
||||
'g:i A' => $this->t('12 hour - @format (@time)', ['@format' => 'g:i A', '@time' => date('g:i A')]),
|
||||
'H:i:s' => $this->t('24 hour with seconds - @format (@time)', ['@format' => 'H:i:s', '@time' => static::formatDate('H:i:s')]),
|
||||
'H:i' => $this->t('24 hour - @format (@time)', ['@format' => 'H:i', '@time' => static::formatDate('H:i')]),
|
||||
'g:i:s A' => $this->t('12 hour with seconds - @format (@time)', ['@format' => 'g:i:s A', '@time' => static::formatDate('g:i:s A')]),
|
||||
'g:i A' => $this->t('12 hour - @format (@time)', ['@format' => 'g:i A', '@time' => static::formatDate('g:i A')]),
|
||||
],
|
||||
'#other__option_label' => $this->t('Custom…'),
|
||||
'#other__placeholder' => $this->t('Custom time format…'),
|
||||
|
@ -286,7 +283,7 @@ class DateTime extends DateBase {
|
|||
$form['time']['date_time_container'] = $this->getFormInlineContainer();
|
||||
$form['time']['date_time_container']['date_time_min'] = [
|
||||
'#type' => 'webform_time',
|
||||
'#title' => $this->t('Time min'),
|
||||
'#title' => $this->t('Time minimum'),
|
||||
'#description' => $this->t('Specifies the minimum time.'),
|
||||
'#states' => [
|
||||
'invisible' => [
|
||||
|
@ -296,7 +293,7 @@ class DateTime extends DateBase {
|
|||
];
|
||||
$form['time']['date_time_container']['date_time_max'] = [
|
||||
'#type' => 'webform_time',
|
||||
'#title' => $this->t('Time max'),
|
||||
'#title' => $this->t('Time maximum'),
|
||||
'#description' => $this->t('Specifies the maximum time.'),
|
||||
'#states' => [
|
||||
'invisible' => [
|
||||
|
@ -318,6 +315,11 @@ class DateTime extends DateBase {
|
|||
],
|
||||
'#other__type' => 'number',
|
||||
'#other__description' => $this->t('Enter interval in seconds.'),
|
||||
'#states' => [
|
||||
'invisible' => [
|
||||
[':input[name="properties[date_time_element]"]' => ['value' => 'none']],
|
||||
],
|
||||
],
|
||||
];
|
||||
return $form;
|
||||
}
|
||||
|
@ -377,25 +379,4 @@ class DateTime extends DateBase {
|
|||
return $properties;
|
||||
}
|
||||
|
||||
/**
|
||||
* After build handler for Datetime elements.
|
||||
*/
|
||||
public static function afterBuildDateTime(array $element, FormStateInterface $form_state) {
|
||||
if (isset($element['time'])) {
|
||||
if (!empty($element['#date_time_min'])) {
|
||||
$element['time']['#min'] = $element['#date_time_min'];
|
||||
$element['time']['#attributes']['min'] = $element['#date_time_min'];
|
||||
}
|
||||
if (!empty($element['#date_time_max'])) {
|
||||
$element['time']['#max'] = $element['#date_time_max'];
|
||||
$element['time']['#attributes']['max'] = $element['#date_time_max'];
|
||||
}
|
||||
if (!empty($element['#date_time_step'])) {
|
||||
$element['time']['#max'] = $element['#date_time_step'];
|
||||
$element['time']['#attributes']['step'] = $element['#date_time_step'];
|
||||
}
|
||||
}
|
||||
return $element;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -61,14 +61,14 @@ abstract class NumericBase extends WebformElementBase {
|
|||
$form['number']['number_container'] = $this->getFormInlineContainer();
|
||||
$form['number']['number_container']['min'] = [
|
||||
'#type' => 'number',
|
||||
'#title' => $this->t('Min'),
|
||||
'#title' => $this->t('Minimum'),
|
||||
'#description' => $this->t('Specifies the minimum value.'),
|
||||
'#step' => 'any',
|
||||
'#size' => 4,
|
||||
];
|
||||
$form['number']['number_container']['max'] = [
|
||||
'#type' => 'number',
|
||||
'#title' => $this->t('Max'),
|
||||
'#title' => $this->t('Maximum'),
|
||||
'#description' => $this->t('Specifies the maximum value.'),
|
||||
'#step' => 'any',
|
||||
'#size' => 4,
|
||||
|
|
|
@ -555,6 +555,28 @@ abstract class OptionsBase extends WebformElementBase {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getElementSelectorSourceValues(array $element) {
|
||||
if ($this->hasMultipleValues($element) && $this->hasMultipleWrapper()) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$plugin_id = $this->getPluginId();
|
||||
$name = $element['#webform_key'];
|
||||
$options = OptGroup::flattenOptions($element['#options']);
|
||||
if ($inputs = $this->getElementSelectorInputsOptions($element)) {
|
||||
$other_type = $this->getOptionsOtherType();
|
||||
$multiple = ($this->hasMultipleValues($element) && $other_type === 'select') ? '[]' : '';
|
||||
return [":input[name=\"{$name}[$other_type]$multiple\"]" => $options];
|
||||
}
|
||||
else {
|
||||
$multiple = ($this->hasMultipleValues($element) && strpos($plugin_id, 'select') !== FALSE) ? '[]' : '';
|
||||
return [":input[name=\"$name$multiple\"]" => $options];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
|
@ -664,9 +686,9 @@ abstract class OptionsBase extends WebformElementBase {
|
|||
$default_empty_option = $this->configFactory->get('webform.settings')->get('element.default_empty_option');
|
||||
if ($default_empty_option) {
|
||||
$default_empty_option_required = $this->configFactory->get('webform.settings')->get('element.default_empty_option_required') ?: $this->t('- Select -');
|
||||
$form['options']['empty_option']['#description'] .= '<br />' . $this->t('Required elements default to: %required', ['%required' => $default_empty_option_required]);
|
||||
$form['options']['empty_option']['#description'] .= '<br />' . $this->t('Required elements defaults to: %required', ['%required' => $default_empty_option_required]);
|
||||
$default_empty_option_optional = $this->configFactory->get('webform.settings')->get('element.default_empty_option_optional') ?: $this->t('- None -');
|
||||
$form['options']['empty_option']['#description'] .= '<br />' . $this->t('Optional elements default to: %optional', ['%optional' => $default_empty_option_optional]);
|
||||
$form['options']['empty_option']['#description'] .= '<br />' . $this->t('Optional elements defaults to: %optional', ['%optional' => $default_empty_option_optional]);
|
||||
}
|
||||
$form['options']['empty_value'] = [
|
||||
'#type' => 'textfield',
|
||||
|
@ -786,7 +808,7 @@ abstract class OptionsBase extends WebformElementBase {
|
|||
$form['options_other']['other__number_container'] = $this->getFormInlineContainer();
|
||||
$form['options_other']['other__number_container']['other__min'] = [
|
||||
'#type' => 'number',
|
||||
'#title' => $this->t('Other min'),
|
||||
'#title' => $this->t('Other minimum'),
|
||||
'#description' => $this->t('Specifies the minimum value.'),
|
||||
'#step' => 'any',
|
||||
'#size' => 4,
|
||||
|
@ -794,7 +816,7 @@ abstract class OptionsBase extends WebformElementBase {
|
|||
];
|
||||
$form['options_other']['other__number_container']['other__max'] = [
|
||||
'#type' => 'number',
|
||||
'#title' => $this->t('Other max'),
|
||||
'#title' => $this->t('Other maximum'),
|
||||
'#description' => $this->t('Specifies the maximum value.'),
|
||||
'#step' => 'any',
|
||||
'#size' => 4,
|
||||
|
|
|
@ -90,6 +90,13 @@ abstract class TextBase extends WebformElementBase {
|
|||
else {
|
||||
$element['#attributes']['data-inputmask-mask'] = $input_mask;
|
||||
}
|
||||
// Set input mask #pattern.
|
||||
$input_masks = $this->getInputMasks();
|
||||
if (isset($input_masks[$input_mask])
|
||||
&& isset($input_masks[$input_mask]['pattern']) &&
|
||||
empty($element['#pattern'])) {
|
||||
$element['#pattern'] = $input_masks[$input_mask]['pattern'];
|
||||
}
|
||||
|
||||
$element['#attributes']['class'][] = 'js-webform-input-mask';
|
||||
$element['#attached']['library'][] = 'webform/webform.element.inputmask';
|
||||
|
@ -132,26 +139,7 @@ abstract class TextBase extends WebformElementBase {
|
|||
'#other__placeholder' => $this->t('Enter input mask…'),
|
||||
'#other__description' => $this->t('(9 = numeric; a = alphabetical; * = alphanumeric)'),
|
||||
'#empty_option' => $this->t('- None -'),
|
||||
'#options' => [
|
||||
'Basic' => [
|
||||
"'alias': 'currency'" => $this->t('Currency - @format', ['@format' => '$ 9.99']),
|
||||
"'alias': 'datetime'" => $this->t('Date - @format', ['@format' => "2007-06-09'T'17:46:21"]),
|
||||
"'alias': 'decimal'" => $this->t('Decimal - @format', ['@format' => '1.234']),
|
||||
"'alias': 'email'" => $this->t('Email - @format', ['@format' => 'example@example.com']),
|
||||
"'alias': 'percentage'" => $this->t('Percentage - @format', ['@format' => '99%']),
|
||||
'(999) 999-9999' => $this->t('Phone - @format', ['@format' => '(999) 999-9999']),
|
||||
'99999[-9999]' => $this->t('ZIP Code - @format', ['@format' => '99999[-9999]']),
|
||||
],
|
||||
'Advanced' => [
|
||||
"'alias': 'ip'" => $this->t('IP address - @format', ['@format' => '255.255.255.255']),
|
||||
'[9-]AAA-999' => $this->t('License plate - @format', ['@format' => '[9-]AAA-999']),
|
||||
"'alias': 'mac'" => $this->t('MAC addresses - @format', ['@format' => '99-99-99-99-99-99']),
|
||||
'999-99-9999' => $this->t('SSN - @format', ['@format' => '999-99-9999']),
|
||||
"'alias': 'vin'" => $this->t('VIN (Vehicle identification number)'),
|
||||
"'casing': 'upper'" => $this->t('Uppercase - UPPERCASE'),
|
||||
"'casing': 'lower'" => $this->t('Lowercase - lowercase'),
|
||||
],
|
||||
],
|
||||
'#options' => $this->getInputMaskOptions(),
|
||||
];
|
||||
if ($this->librariesManager->isExcluded('jquery.inputmask')) {
|
||||
$form['form']['input_mask']['#access'] = FALSE;
|
||||
|
@ -290,9 +278,105 @@ abstract class TextBase extends WebformElementBase {
|
|||
}
|
||||
|
||||
// Validate #counter_maximum.
|
||||
if (!empty($properties['#counter_type']) && empty($properties['#counter_maximum'])) {
|
||||
$form_state->setErrorByName('counter_maximum', t('Counter maximum is required.'));
|
||||
if (!empty($properties['#counter_type']) && empty($properties['#counter_maximum']) && empty($properties['#counter_minimum'])) {
|
||||
$form_state->setErrorByName('counter_minimum', t('Counter minimum or maximum is required.'));
|
||||
$form_state->setErrorByName('counter_maximum', t('Counter minimum or maximum is required.'));
|
||||
}
|
||||
}
|
||||
|
||||
/****************************************************************************/
|
||||
// Input masks.
|
||||
/****************************************************************************/
|
||||
|
||||
/**
|
||||
* Get input masks.
|
||||
*
|
||||
* @return array
|
||||
* An associative array keyed my input mask contain input mask title,
|
||||
* example, and patterh.
|
||||
*/
|
||||
protected function getInputMasks() {
|
||||
return [
|
||||
"'alias': 'currency'" => [
|
||||
'title' => $this->t('Currency'),
|
||||
'example' => '$ 9.99',
|
||||
'pattern' => '^\$ \d+.\d\d$',
|
||||
],
|
||||
"'alias': 'datetime'" => [
|
||||
'title' => $this->t('Date'),
|
||||
'example' => '2007-06-09\'T\'17:46:21',
|
||||
],
|
||||
"'alias': 'decimal'" => [
|
||||
'title' => $this->t('Decimal'),
|
||||
'example' => '1.234',
|
||||
'pattern' => '^\d+(\.\d+)?$',
|
||||
],
|
||||
"'alias': 'email'" => [
|
||||
'title' => $this->t('Email'),
|
||||
'example' => 'example@example.com',
|
||||
],
|
||||
"'alias': 'ip'" => [
|
||||
'title' => $this->t('IP address'),
|
||||
'example' => '255.255.255.255',
|
||||
'pattern' => '^\d\d\d\.\d\d\d\.\d\d\d\.\d\d\d$',
|
||||
],
|
||||
'[9-]AAA-999' => [
|
||||
'title' => $this->t('License plate'),
|
||||
'example' => '[9-]AAA-999',
|
||||
],
|
||||
"'alias': 'mac'" => [
|
||||
'title' => $this->t('MAC address'),
|
||||
'example' => '99-99-99-99-99-99',
|
||||
'pattern' => '^\d\d-\d\d-\d\d-\d\d-\d\d-\d\d$',
|
||||
],
|
||||
"'alias': 'percentage'" => [
|
||||
'title' => $this->t('Percentage'),
|
||||
'example' => '99 %',
|
||||
'pattern' => '^\d+ %$',
|
||||
],
|
||||
'(999) 999-9999' => [
|
||||
'title' => $this->t('Phone'),
|
||||
'example' => '(999) 999-9999',
|
||||
'pattern' => '^\(\d\d\d\) \d\d\d-\d\d\d\d$',
|
||||
],
|
||||
'999-99-9999' => [
|
||||
'title' => $this->t('Social Security Number (SSN)'),
|
||||
'example' => '999-99-9999',
|
||||
'pattern' => '^\d\d\d-\d\d-\d\d\d\d$',
|
||||
],
|
||||
"'alias': 'vin'" => [
|
||||
'title' => $this->t('Vehicle identification number (VIN)'),
|
||||
'example' => 'JA3AY11A82U020534',
|
||||
],
|
||||
'99999[-9999]' => [
|
||||
'title' => $this->t('ZIP Code'),
|
||||
'example' => '99999[-9999]',
|
||||
'pattern' => '^\d\d\d\d\d(-\d\d\d\d)?$',
|
||||
],
|
||||
"'casing': 'upper'" => [
|
||||
'title' => $this->t('Uppercase'),
|
||||
'example' => 'UPPERCASE',
|
||||
],
|
||||
"'casing': 'lower'" => [
|
||||
'title' => $this->t('Lowercase '),
|
||||
'example' => 'lowercase',
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get input masks as select menu options.
|
||||
*
|
||||
* @return array
|
||||
* An associative array of options.
|
||||
*/
|
||||
protected function getInputMaskOptions() {
|
||||
$input_masks = $this->getInputMasks();
|
||||
$options = [];
|
||||
foreach ($input_masks as $input_mask => $settings) {
|
||||
$options[$input_mask] = $settings['title'] . (!empty($settings['example']) ? ' - ' . $settings['example'] : '');
|
||||
}
|
||||
return $options;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -66,6 +66,7 @@ class Textarea extends TextBase {
|
|||
'format_items' => $this->getItemsDefaultFormat(),
|
||||
'format_items_html' => '',
|
||||
'format_items_text' => '',
|
||||
'format_attributes' => [],
|
||||
] + parent::getDefaultProperties() + $this->getDefaultMultipleProperties();
|
||||
}
|
||||
|
||||
|
|
|
@ -28,6 +28,7 @@ class WebformCodeMirror extends WebformElementBase {
|
|||
// Codemirror settings.
|
||||
'placeholder' => '',
|
||||
'mode' => 'text',
|
||||
'wrap' => TRUE,
|
||||
] + parent::getDefaultProperties();
|
||||
}
|
||||
|
||||
|
@ -130,6 +131,11 @@ class WebformCodeMirror extends WebformElementBase {
|
|||
],
|
||||
'#required' => TRUE,
|
||||
];
|
||||
$form['codemirror']['wrap'] = [
|
||||
'#title' => $this->t('Wrap for long lines'),
|
||||
'#type' => 'checkbox',
|
||||
'#return_value' => TRUE,
|
||||
];
|
||||
return $form;
|
||||
}
|
||||
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
namespace Drupal\webform\Plugin\WebformElement;
|
||||
|
||||
use Drupal\Core\Form\FormStateInterface;
|
||||
use Drupal\Core\Form\OptGroup;
|
||||
use Drupal\Core\Render\Element as RenderElement;
|
||||
use Drupal\Core\Render\Element;
|
||||
use Drupal\Core\StringTranslation\TranslatableMarkup;
|
||||
|
@ -267,27 +268,36 @@ abstract class WebformCompositeBase extends WebformElementBase {
|
|||
$has_access = (!isset($composite_elements['#access']) || $composite_elements['#access']);
|
||||
if ($has_access && isset($composite_element['#type'])) {
|
||||
$element_plugin = $this->elementManager->getElementInstance($composite_element);
|
||||
$composite_title = (isset($composite_element['#title'])) ? $composite_element['#title'] : $composite_key;
|
||||
|
||||
switch ($composite_element['#type']) {
|
||||
case 'label':
|
||||
case 'webform_message':
|
||||
break;
|
||||
|
||||
case 'webform_select_other':
|
||||
$selectors[":input[name=\"{$name}[{$composite_key}][select]\"]"] = $composite_title . ' [' . $this->t('Select') . ']';
|
||||
$selectors[":input[name=\"{$name}[{$composite_key}][other]\"]"] = $composite_title . ' [' . $this->t('Textfield') . ']';
|
||||
break;
|
||||
|
||||
default:
|
||||
$selectors[":input[name=\"{$name}[{$composite_key}]\"]"] = $composite_title . ' [' . $element_plugin->getPluginLabel() . ']';
|
||||
break;
|
||||
}
|
||||
$composite_element['#webform_key'] = "{$name}[{$composite_key}]";
|
||||
$selectors += OptGroup::flattenOptions($element_plugin->getElementSelectorOptions($composite_element));
|
||||
}
|
||||
}
|
||||
return [$title => $selectors];
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getElementSelectorSourceValues(array $element) {
|
||||
if ($this->hasMultipleValues($element)) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$name = $element['#webform_key'];
|
||||
|
||||
$source_values = [];
|
||||
$composite_elements = $this->getInitializedCompositeElement($element);
|
||||
foreach ($composite_elements as $composite_key => $composite_element) {
|
||||
$has_access = (!isset($composite_elements['#access']) || $composite_elements['#access']);
|
||||
if ($has_access && isset($composite_element['#type'])) {
|
||||
$element_plugin = $this->elementManager->getElementInstance($composite_element);
|
||||
$composite_element['#webform_key'] = "{$name}[{$composite_key}]";
|
||||
$source_values += $element_plugin->getElementSelectorSourceValues($composite_element);
|
||||
}
|
||||
}
|
||||
return $source_values;
|
||||
}
|
||||
|
||||
/****************************************************************************/
|
||||
// Display submission value methods.
|
||||
/****************************************************************************/
|
||||
|
|
|
@ -39,7 +39,7 @@ abstract class WebformComputedBase extends WebformElementBase implements Webform
|
|||
'title_display' => '',
|
||||
'description_display' => '',
|
||||
// Computed values.
|
||||
'value' => '',
|
||||
'template' => '',
|
||||
'mode' => WebformComputedBaseElement::MODE_AUTO,
|
||||
'hide_empty' => FALSE,
|
||||
'store' => FALSE,
|
||||
|
@ -84,7 +84,7 @@ abstract class WebformComputedBase extends WebformElementBase implements Webform
|
|||
*/
|
||||
public function replaceTokens(array &$element, EntityInterface $entity = NULL) {
|
||||
foreach ($element as $key => $value) {
|
||||
if (!Element::child($key) && !in_array($key, ['#value'])) {
|
||||
if (!Element::child($key) && !in_array($key, ['#template'])) {
|
||||
$element[$key] = $this->tokenManager->replace($value, $entity);
|
||||
}
|
||||
}
|
||||
|
@ -152,7 +152,7 @@ abstract class WebformComputedBase extends WebformElementBase implements Webform
|
|||
return [
|
||||
'#type' => $this->getTypeName(),
|
||||
'#title' => $this->getPluginLabel(),
|
||||
'#value' => $this->t('This is a @label value.', ['@label' => $this->getPluginLabel()]),
|
||||
'#template' => $this->t('This is a @label value.', ['@label' => $this->getPluginLabel()]),
|
||||
];
|
||||
}
|
||||
|
||||
|
@ -162,9 +162,6 @@ abstract class WebformComputedBase extends WebformElementBase implements Webform
|
|||
public function form(array $form, FormStateInterface $form_state) {
|
||||
$form = parent::form($form, $form_state);
|
||||
|
||||
// Remove value element so that it appears under computed fieldset.
|
||||
unset($form['element']['value']);
|
||||
|
||||
$form['computed'] = [
|
||||
'#type' => 'fieldset',
|
||||
'#title' => $this->t('Computed settings'),
|
||||
|
@ -192,7 +189,7 @@ abstract class WebformComputedBase extends WebformElementBase implements Webform
|
|||
WebformComputedBaseElement::MODE_TEXT => t('Plain text'),
|
||||
],
|
||||
];
|
||||
$form['computed']['value'] = [
|
||||
$form['computed']['template'] = [
|
||||
'#type' => 'webform_codemirror',
|
||||
'#mode' => 'text',
|
||||
'#title' => $this->t('Computed value/markup'),
|
||||
|
@ -329,4 +326,11 @@ abstract class WebformComputedBase extends WebformElementBase implements Webform
|
|||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getElementSelectorInputValue($selector, $trigger, array $element, WebformSubmissionInterface $webform_submission) {
|
||||
return (string) $this->processValue($element, $webform_submission);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -34,7 +34,7 @@ class WebformComputedTwig extends WebformComputedBase {
|
|||
$form = parent::form($form, $form_state);
|
||||
|
||||
$form['computed']['help'] = TwigExtension::buildTwigHelp();
|
||||
$form['computed']['value']['#mode'] = 'twig';
|
||||
$form['computed']['template']['#mode'] = 'twig';
|
||||
|
||||
// Set #access so that help is always visible.
|
||||
WebformElementHelper::setPropertyRecursive($form['computed']['help'], '#access', TRUE);
|
||||
|
|
|
@ -39,4 +39,12 @@ trait WebformEntityOptionsTrait {
|
|||
return parent::getElementSelectorInputsOptions($element);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getElementSelectorSourceValues(array $element) {
|
||||
$this->setOptions($element);
|
||||
return parent::getElementSelectorSourceValues($element);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -135,10 +135,10 @@ trait WebformEntityReferenceTrait {
|
|||
* {@inheritdoc}
|
||||
*/
|
||||
public function getTestValues(array $element, WebformInterface $webform, array $options = []) {
|
||||
$this->setOptions($element);
|
||||
$target_type = $this->getTargetType($element);
|
||||
$this->setOptions($element, ['limit' => 10, 'random' => TRUE]);
|
||||
// Exclude 'anonymous' user.
|
||||
if ($target_type == 'user') {
|
||||
$target_type = $this->getTargetType($element);
|
||||
if ($target_type === 'user') {
|
||||
unset($element['#options'][0]);
|
||||
}
|
||||
return array_keys($element['#options']);
|
||||
|
@ -345,9 +345,11 @@ trait WebformEntityReferenceTrait {
|
|||
*
|
||||
* @param array $element
|
||||
* An element.
|
||||
* @param array $settings
|
||||
* An array of settings used to limit and randomize options.
|
||||
*/
|
||||
protected function setOptions(array &$element) {
|
||||
WebformEntityTrait::setOptions($element);
|
||||
protected function setOptions(array &$element, array $settings = []) {
|
||||
WebformEntityTrait::setOptions($element, $settings);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -50,6 +50,7 @@ class WebformLikert extends WebformElementBase {
|
|||
'format' => $this->getItemDefaultFormat(),
|
||||
'format_html' => '',
|
||||
'format_text' => '',
|
||||
'format_attributes' => [],
|
||||
// Likert settings.
|
||||
'sticky' => TRUE,
|
||||
'questions' => [],
|
||||
|
@ -385,6 +386,20 @@ class WebformLikert extends WebformElementBase {
|
|||
return $selectors;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getElementSelectorSourceValues(array $element) {
|
||||
$selector_options = $this->getElementSelectorOptions($element);
|
||||
$selectors = reset($selector_options);
|
||||
|
||||
$source_values = [];
|
||||
foreach (array_keys($selectors) as $selector) {
|
||||
$source_values[$selector] = $element['#answers'];
|
||||
}
|
||||
return $source_values;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
namespace Drupal\webform\Plugin\WebformElement;
|
||||
|
||||
use Drupal\Component\Utility\Bytes;
|
||||
use Drupal\Component\Utility\Html;
|
||||
use Drupal\Component\Utility\Unicode;
|
||||
use Drupal\Component\Transliteration\TransliterationInterface;
|
||||
use Drupal\Core\Config\ConfigFactoryInterface;
|
||||
|
@ -19,8 +20,10 @@ use Drupal\Core\Session\AccountInterface;
|
|||
use Drupal\Core\StreamWrapper\StreamWrapperInterface;
|
||||
use Drupal\file\Entity\File;
|
||||
use Drupal\file\FileInterface;
|
||||
use Drupal\webform\Element\WebformHtmlEditor;
|
||||
use Drupal\webform\Entity\WebformSubmission;
|
||||
use Drupal\webform\Plugin\WebformElementBase;
|
||||
use Drupal\webform\Utility\WebformOptionsHelper;
|
||||
use Drupal\webform\WebformInterface;
|
||||
use Drupal\webform\WebformSubmissionForm;
|
||||
use Drupal\webform\WebformSubmissionInterface;
|
||||
|
@ -153,6 +156,9 @@ abstract class WebformManagedFileBase extends WebformElementBase implements Webf
|
|||
'max_filesize' => '',
|
||||
'file_extensions' => $file_extensions,
|
||||
'file_name' => '',
|
||||
'file_help' => '',
|
||||
'file_preview' => '',
|
||||
'file_placeholder' => '',
|
||||
'uri_scheme' => 'private',
|
||||
'sanitize' => FALSE,
|
||||
'button' => FALSE,
|
||||
|
@ -281,19 +287,35 @@ abstract class WebformManagedFileBase extends WebformElementBase implements Webf
|
|||
$element['#upload_validators']['file_validate_size'] = [$this->getMaxFileSize($element)];
|
||||
$element['#upload_validators']['file_validate_extensions'] = [$this->getFileExtensions($element)];
|
||||
|
||||
// Add file upload help to the element.
|
||||
// Add file upload help to the element as #description, #help, or #more.
|
||||
// Copy upload validator so that we can add webform's file limit to
|
||||
// file upload help only.
|
||||
$upload_validators = $element['#upload_validators'];
|
||||
// Add webform file limit to help.
|
||||
if ($file_limit) {
|
||||
$upload_validators['webform_file_limit'] = [Bytes::toInt($file_limit)];
|
||||
}
|
||||
$element['help'] = [
|
||||
$file_upload_help = [
|
||||
'#theme' => 'file_upload_help',
|
||||
'#upload_validators' => $upload_validators,
|
||||
'#cardinality' => (empty($element['#multiple'])) ? 1 : $element['#multiple'],
|
||||
'#prefix' => '<div class="description">',
|
||||
'#suffix' => '</div>',
|
||||
];
|
||||
$file_help = (isset($element['#file_help'])) ? $element['#file_help'] : 'description';
|
||||
if ($file_help !== 'none') {
|
||||
if (isset($element["#$file_help"])) {
|
||||
if (is_array($element["#$file_help"])) {
|
||||
$file_help_content = $element["#$file_help"];
|
||||
}
|
||||
else {
|
||||
$file_help_content = ['#markup' => $element["#$file_help"]];
|
||||
}
|
||||
$file_help_content += ['#suffix' => '<br/>'];
|
||||
$element["#$file_help"] = ['content' => $file_help_content];
|
||||
}
|
||||
else {
|
||||
$element["#$file_help"] = [];
|
||||
}
|
||||
$element["#$file_help"]['file_upload_help'] = $file_upload_help;
|
||||
}
|
||||
|
||||
// Issue #2705471: Webform states File fields.
|
||||
// Workaround: Wrap the 'managed_file' element in a basic container.
|
||||
|
@ -307,8 +329,11 @@ abstract class WebformManagedFileBase extends WebformElementBase implements Webf
|
|||
$element = $container;
|
||||
}
|
||||
|
||||
// Add after build handler.
|
||||
$element['#after_build'][] = [get_class($this), 'afterBuildManagedFile'];
|
||||
// Add process callback.
|
||||
// Set element's #process callback so that is not replaced by
|
||||
// additional #process callbacks.
|
||||
$this->setElementDefaultCallback($element, 'process');
|
||||
$element['#process'][] = [get_class($this), 'processManagedFile'];
|
||||
|
||||
// Add managed file upload tracking.
|
||||
if (\Drupal::moduleHandler()->moduleExists('file')) {
|
||||
|
@ -583,19 +608,25 @@ abstract class WebformManagedFileBase extends WebformElementBase implements Webf
|
|||
}
|
||||
|
||||
/**
|
||||
* Get allowed file extensions for an element.
|
||||
* Get the allowed file extensions for an element.
|
||||
*
|
||||
* @param array $element
|
||||
* An element.
|
||||
*
|
||||
* @return int
|
||||
* File extension.
|
||||
* File extensions.
|
||||
*/
|
||||
protected function getFileExtensions(array $element = NULL) {
|
||||
if (!empty($element['#file_extensions'])) {
|
||||
return $element['#file_extensions'];
|
||||
}
|
||||
return (!empty($element['#file_extensions'])) ? $element['#file_extensions'] : $this->getDefaultFileExtensions();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the default allowed file extensions.
|
||||
*
|
||||
* @return int
|
||||
* File extensions.
|
||||
*/
|
||||
protected function getDefaultFileExtensions() {
|
||||
$file_type = str_replace('webform_', '', $this->getPluginId());
|
||||
return $this->configFactory->get('webform.settings')->get("file.default_{$file_type}_extensions");
|
||||
}
|
||||
|
@ -658,9 +689,9 @@ abstract class WebformManagedFileBase extends WebformElementBase implements Webf
|
|||
}
|
||||
|
||||
/**
|
||||
* After build handler for managed file elements.
|
||||
* Process callback for managed file elements.
|
||||
*/
|
||||
public static function afterBuildManagedFile(array $element, FormStateInterface $form_state) {
|
||||
public static function processManagedFile(&$element, FormStateInterface $form_state, &$complete_form) {
|
||||
// Disable inline form errors for multiple file upload checkboxes.
|
||||
if (!empty($element['#multiple'])) {
|
||||
foreach (Element::children($element) as $key) {
|
||||
|
@ -669,9 +700,110 @@ abstract class WebformManagedFileBase extends WebformElementBase implements Webf
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Preview uploaded file.
|
||||
if (!empty($element['#file_preview'])) {
|
||||
// Get the element's plugin object.
|
||||
/** @var \Drupal\webform\Plugin\WebformElementManagerInterface $element_manager */
|
||||
$element_manager = \Drupal::service('plugin.manager.webform.element');
|
||||
/** @var \Drupal\webform\Plugin\WebformElement\WebformManagedFileBase $element_plugin */
|
||||
$element_plugin = $element_manager->getElementInstance($element);
|
||||
|
||||
|
||||
// Get the webform submission.
|
||||
/** @var \Drupal\webform\WebformSubmissionForm $form_object */
|
||||
$form_object = $form_state->getFormObject();
|
||||
/** @var \Drupal\webform\webform_submission $webform_submission */
|
||||
$webform_submission = $form_object->getEntity();
|
||||
|
||||
// Create a temporary preview element with an overridden #format.
|
||||
$preview_element = ['#format' => $element['#file_preview']] + $element;
|
||||
|
||||
// Convert '#theme': file_link to a container with a file preview.
|
||||
$delta = 0;
|
||||
foreach (Element::children($element) as $child_key) {
|
||||
if (strpos($child_key, 'file_') !== 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Set multiple options delta.
|
||||
$options = ['delta' => $delta];
|
||||
$delta++;
|
||||
|
||||
$fid = str_replace('file_', '', $child_key);
|
||||
$file = File::load((string)$fid);
|
||||
// Make sure the file entity exists.
|
||||
if (!$file) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Don't allow anonymous temporary files to be previewed.
|
||||
// @see template_preprocess_file_link().
|
||||
// @see webform_preprocess_file_link().
|
||||
if ($file->isTemporary() && $file->getOwner()->isAnonymous() && strpos($file->getFileUri(), 'private://') === 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$preview = $element_plugin->previewManagedFile($preview_element, $webform_submission, $options);
|
||||
if (isset($element[$child_key]['filename'])) {
|
||||
// Single file.
|
||||
// Covert file link to a container with preview.
|
||||
unset($element[$child_key]['filename']['#theme']);
|
||||
$element[$child_key]['filename']['#type'] = 'container';
|
||||
$element[$child_key]['filename']['#attributes']['class'][] = 'webform-managed-file-preview';
|
||||
$element[$child_key]['filename']['#attributes']['class'][] = Html::getClass($element['#type'] . '-preview');
|
||||
$element[$child_key]['filename']['preview'] = $preview;
|
||||
}
|
||||
elseif (isset($element[$child_key]['selected'])) {
|
||||
// Multiple files.
|
||||
// Convert file link checkbox #title to preview.
|
||||
$element[$child_key]['selected']['#wrapper_attributes']['class'][] = 'webform-managed-file-preview-wrapper';
|
||||
$element[$child_key]['selected']['#wrapper_attributes']['class'][] = Html::getClass($element['#type'] . '-preview-wrapper');
|
||||
$element[$child_key]['selected']['#label_attributes']['class'][] = 'webform-managed-file-preview';
|
||||
$element[$child_key]['selected']['#label_attributes']['class'][] = Html::getClass($element['#type'] . '-preview');
|
||||
|
||||
$element[$child_key]['selected']['#title'] = \Drupal::service('renderer')->render($preview);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// File placeholder.
|
||||
if (!empty($element['#file_placeholder']) && (empty($element['#value']) || empty($element['#value']['fids']))) {
|
||||
$element['file_placeholder'] = [
|
||||
'#type' => 'container',
|
||||
'#attributes' => [
|
||||
'class' => [
|
||||
'webform-managed-file-placeholder',
|
||||
Html::getClass($element['#type'] . '-placeholder'),
|
||||
],
|
||||
],
|
||||
// Display placeholder before file upload input.
|
||||
'#weight' => ($element['upload']['#weight'] - 1),
|
||||
'content' => WebformHtmlEditor::checkMarkup($element['#file_placeholder']),
|
||||
];
|
||||
}
|
||||
|
||||
return $element;
|
||||
}
|
||||
|
||||
/**
|
||||
* Preview a managed file element upload.
|
||||
*
|
||||
* @param array $element
|
||||
* An element.
|
||||
* @param \Drupal\webform\WebformSubmissionInterface $webform_submission
|
||||
* A webform submission.
|
||||
* @param array $options
|
||||
* An array of options.
|
||||
*
|
||||
* @return string|array
|
||||
* A preview.
|
||||
*/
|
||||
public function previewManagedFile(array $element, WebformSubmissionInterface $webform_submission, array $options = []) {
|
||||
$build = $this->formatHtmlItem($element, $webform_submission, $options);
|
||||
return (is_array($build)) ? $build : ['#markup' => $build];
|
||||
}
|
||||
|
||||
/**
|
||||
* Form API callback. Consolidate the array of fids for this field into a single fids.
|
||||
*/
|
||||
|
@ -791,7 +923,7 @@ abstract class WebformManagedFileBase extends WebformElementBase implements Webf
|
|||
$scheme_options = static::getVisibleStreamWrappers();
|
||||
$form['file']['uri_scheme'] = [
|
||||
'#type' => 'radios',
|
||||
'#title' => t('Upload destination'),
|
||||
'#title' => t('File upload destination'),
|
||||
'#description' => t('Select where the final files should be stored. Private file storage has more overhead than public files, but allows restricted access to files within this element.'),
|
||||
'#required' => TRUE,
|
||||
'#options' => $scheme_options,
|
||||
|
@ -824,6 +956,31 @@ abstract class WebformManagedFileBase extends WebformElementBase implements Webf
|
|||
$max_filesize = \Drupal::config('webform.settings')->get('file.default_max_filesize') ?: file_upload_max_size();
|
||||
$max_filesize = Bytes::toInt($max_filesize);
|
||||
$max_filesize = ($max_filesize / 1024 / 1024);
|
||||
$form['file']['file_help'] = [
|
||||
'#type' => 'select',
|
||||
'#title' => $this->t('File upload help display'),
|
||||
'#description' => $this->t('Determines the placement of the file upload help .'),
|
||||
'#options' => [
|
||||
'' => $this->t('Description'),
|
||||
'help' => $this->t('Help'),
|
||||
'more' => $this->t('More'),
|
||||
'none' => $this->t('None'),
|
||||
],
|
||||
];
|
||||
$form['file']['file_placeholder'] = [
|
||||
'#type' => 'webform_html_editor',
|
||||
'#title' => $this->t('File upload placeholder'),
|
||||
'#description' => $this->t('The placeholder will be shown before a file is uploaded.'),
|
||||
];
|
||||
$form['file']['file_preview'] = [
|
||||
'#type' => 'select',
|
||||
'#title' => $this->t('File upload preview (Authenticated users only)'),
|
||||
'#description' => $this->t('Select how the uploaded file previewed.') . '<br/><br/>' .
|
||||
$this->t('Allowing anonymous users to preview files is dangerous.') . '<br/>' .
|
||||
$this->t('For more information see: <a href="https://www.drupal.org/psa-2016-003">DRUPAL-PSA-2016-003</a>'),
|
||||
'#options' => WebformOptionsHelper::appendValueToText($this->getItemFormats()),
|
||||
'#empty_option' => '<' . $this->t('no preview') . '>',
|
||||
];
|
||||
$form['file']['max_filesize'] = [
|
||||
'#type' => 'number',
|
||||
'#title' => $this->t('Maximum file size'),
|
||||
|
@ -836,7 +993,8 @@ abstract class WebformManagedFileBase extends WebformElementBase implements Webf
|
|||
$form['file']['file_extensions'] = [
|
||||
'#type' => 'textfield',
|
||||
'#title' => $this->t('Allowed file extensions'),
|
||||
'#description' => $this->t('Separate extensions with a space and do not include the leading dot.'),
|
||||
'#description' => $this->t('Separate extensions with a space and do not include the leading dot.') . '<br/><br/>' .
|
||||
$this->t('Defaults to: %value', ['%value' => $this->getDefaultFileExtensions()]),
|
||||
'#maxlength' => 255,
|
||||
];
|
||||
$form['file']['file_name'] = [
|
||||
|
@ -888,7 +1046,7 @@ abstract class WebformManagedFileBase extends WebformElementBase implements Webf
|
|||
];
|
||||
$form['file']['button__title'] = [
|
||||
'#type' => 'textfield',
|
||||
'#title' => $this->t('Upload button title'),
|
||||
'#title' => $this->t('File upload button title'),
|
||||
'#description' => $this->t('Defaults to: %value', ['%value' => $this->t('Choose file')]),
|
||||
'#states' => [
|
||||
'visible' => [
|
||||
|
@ -898,7 +1056,7 @@ abstract class WebformManagedFileBase extends WebformElementBase implements Webf
|
|||
];
|
||||
$form['file']['button__attributes'] = [
|
||||
'#type' => 'webform_element_attributes',
|
||||
'#title' => $this->t('Upload button attributes'),
|
||||
'#title' => $this->t('File upload button'),
|
||||
'#classes' => $this->configFactory->get('webform.settings')->get('settings.button_classes'),
|
||||
'#class__description' => $this->t("Apply classes to the button. Button classes default to 'button button-primary'."),
|
||||
'#states' => [
|
||||
|
|
|
@ -52,6 +52,7 @@ class WebformMapping extends WebformElementBase {
|
|||
'format' => $this->getItemDefaultFormat(),
|
||||
'format_html' => '',
|
||||
'format_text' => '',
|
||||
'format_attributes' => [],
|
||||
// Mapping settings.
|
||||
'arrow' => '→',
|
||||
'source' => [],
|
||||
|
|
|
@ -61,6 +61,7 @@ class WebformSection extends ContainerBase {
|
|||
$form['form']['title_tag'] = [
|
||||
'#type' => 'webform_select_other',
|
||||
'#title' => $this->t('Title tag'),
|
||||
'#description' => $this->t("The section's title HTML tag."),
|
||||
'#options' => [
|
||||
'h1' => $this->t('Header 1 (h1)'),
|
||||
'h2' => $this->t('Header 2 (h2)'),
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
namespace Drupal\webform\Plugin\WebformElement;
|
||||
|
||||
use Drupal\Core\Form\FormStateInterface;
|
||||
use Drupal\Core\Form\OptGroup;
|
||||
use Drupal\webform\Utility\WebformArrayHelper;
|
||||
use Drupal\webform\WebformSubmissionInterface;
|
||||
|
||||
|
@ -82,16 +83,32 @@ trait WebformTableTrait {
|
|||
protected function getTableSelectElementSelectorOptions(array $element, $input_selector = '') {
|
||||
$title = $this->getAdminLabel($element) . ' [' . $this->getPluginLabel() . ']';
|
||||
$name = $element['#webform_key'];
|
||||
$type = ($this->hasMultipleValues($element) ? $this->t('Checkbox') : $this->t('Radio'));
|
||||
|
||||
$selectors = [];
|
||||
foreach ($element['#options'] as $value => $text) {
|
||||
if (is_array($text)) {
|
||||
$text = $value;
|
||||
if ($this->hasMultipleValues($element)) {
|
||||
$selectors = [];
|
||||
foreach ($element['#options'] as $value => $text) {
|
||||
if (is_array($text)) {
|
||||
$text = $value;
|
||||
}
|
||||
$selectors[":input[name=\"{$name}[{$value}]$input_selector\"]"] = $text . ' [' . $this->t('Checkbox') . ']';
|
||||
}
|
||||
$selectors[":input[name=\"{$name}[{$value}]$input_selector\"]"] = $text . ' [' . $type . ']';
|
||||
return [$title => $selectors];
|
||||
}
|
||||
return [$title => $selectors];
|
||||
else {
|
||||
return [":input[name=\"{$name}\"]" => $title];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getElementSelectorSourceValues(array $element) {
|
||||
if ($this->hasMultipleValues($element)) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$name = $element['#webform_key'];
|
||||
$options = OptGroup::flattenOptions($element['#options']);
|
||||
return [":input[name=\"{$name}\"]" => $options];
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -59,7 +59,7 @@ class WebformTime extends WebformElementBase {
|
|||
$format = $this->getItemFormat($element);
|
||||
if ($format == 'value') {
|
||||
$time_format = (isset($element['#time_format'])) ? $element['#time_format'] : 'H:i';
|
||||
return date($time_format, strtotime($value));
|
||||
return static::formatTime($time_format, strtotime($value));
|
||||
}
|
||||
|
||||
return parent::formatTextItem($element, $webform_submission, $options);
|
||||
|
@ -90,10 +90,10 @@ class WebformTime extends WebformElementBase {
|
|||
'#type' => 'webform_select_other',
|
||||
'#title' => $this->t('Time format'),
|
||||
'#options' => [
|
||||
'H:i' => $this->t('24 hour - @format (@time)', ['@format' => 'H:i', '@time' => date('H:i')]),
|
||||
'H:i:s' => $this->t('24 hour with seconds - @format (@time)', ['@format' => 'H:i:s', '@time' => date('H:i:s')]),
|
||||
'g:i A' => $this->t('12 hour - @format (@time)', ['@format' => 'g:i A', '@time' => date('g:i A')]),
|
||||
'g:i:s A' => $this->t('12 hour with seconds - @format (@time)', ['@format' => 'g:i:s A', '@time' => date('g:i:s A')]),
|
||||
'H:i' => $this->t('24 hour - @format (@time)', ['@format' => 'H:i', '@time' => static::formatTime('H:i')]),
|
||||
'H:i:s' => $this->t('24 hour with seconds - @format (@time)', ['@format' => 'H:i:s', '@time' => static::formatTime('H:i:s')]),
|
||||
'g:i A' => $this->t('12 hour - @format (@time)', ['@format' => 'g:i A', '@time' => static::formatTime('g:i A')]),
|
||||
'g:i:s A' => $this->t('12 hour with seconds - @format (@time)', ['@format' => 'g:i:s A', '@time' => static::formatTime('g:i:s A')]),
|
||||
],
|
||||
'#other__option_label' => $this->t('Custom…'),
|
||||
'#other__placeholder' => $this->t('Custom time format…'),
|
||||
|
@ -102,12 +102,12 @@ class WebformTime extends WebformElementBase {
|
|||
$form['time']['time_container'] = $this->getFormInlineContainer();
|
||||
$form['time']['time_container']['min'] = [
|
||||
'#type' => 'webform_time',
|
||||
'#title' => $this->t('Min'),
|
||||
'#title' => $this->t('Minimum'),
|
||||
'#description' => $this->t('Specifies the minimum time.'),
|
||||
];
|
||||
$form['time']['time_container']['max'] = [
|
||||
'#type' => 'webform_time',
|
||||
'#title' => $this->t('Max'),
|
||||
'#title' => $this->t('Maximum'),
|
||||
'#description' => $this->t('Specifies the maximum time.'),
|
||||
];
|
||||
$form['time']['step'] = [
|
||||
|
@ -128,4 +128,21 @@ class WebformTime extends WebformElementBase {
|
|||
return $form;
|
||||
}
|
||||
|
||||
/**
|
||||
* Format custom time.
|
||||
*
|
||||
* @param string $custom_format
|
||||
* A PHP date format string suitable for input to date().
|
||||
* @param int $timestamp
|
||||
* (optional) A UNIX timestamp to format.
|
||||
*
|
||||
* @return string
|
||||
* Formatted time.
|
||||
*/
|
||||
protected static function formatTime($custom_format, $timestamp = NULL) {
|
||||
/** @var \Drupal\Core\Datetime\DateFormatterInterface $date_formatter */
|
||||
$date_formatter = \Drupal::service('date.formatter');
|
||||
return $date_formatter->format($timestamp ?: time(), 'custom', $custom_format);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -221,6 +221,7 @@ class WebformElementBase extends PluginBase implements WebformElementInterface {
|
|||
'format_items' => $this->getItemsDefaultFormat(),
|
||||
'format_items_html' => '',
|
||||
'format_items_text' => '',
|
||||
'format_attributes' => [],
|
||||
];
|
||||
|
||||
// Unique validation.
|
||||
|
@ -1107,6 +1108,7 @@ class WebformElementBase extends PluginBase implements WebformElementInterface {
|
|||
* {@inheritdoc}
|
||||
*/
|
||||
public function getAdminLabel(array $element) {
|
||||
$element += ['#admin_title' => '', '#title' => '', '#webform_key' => ''];
|
||||
return $element['#admin_title'] ?: $element['#title'] ?: $element['#webform_key'];
|
||||
}
|
||||
|
||||
|
@ -1839,11 +1841,20 @@ class WebformElementBase extends PluginBase implements WebformElementInterface {
|
|||
return;
|
||||
}
|
||||
|
||||
/** @var \Drupal\webform\Plugin\WebformElementManagerInterface $element_manager */
|
||||
$element_manager = \Drupal::service('plugin.manager.webform.element');
|
||||
|
||||
$name = $element['#webform_key'];
|
||||
$value = NestedArray::getValue($form_state->getValues(), $element['#parents']);
|
||||
|
||||
// Skip empty unique fields or composite arrays.
|
||||
if ($value === '' || is_array($value)) {
|
||||
// Skip composite elements.
|
||||
$element_plugin = $element_manager->getElementInstance($element);
|
||||
if ($element_plugin->isComposite()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Skip empty values but allow for '0'.
|
||||
if ($value === '' || $value === NULL || (is_array($value) && empty($value))) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -1853,13 +1864,13 @@ class WebformElementBase extends PluginBase implements WebformElementInterface {
|
|||
$webform_submission = $form_object->getEntity();
|
||||
$webform = $webform_submission->getWebform();
|
||||
|
||||
// Build unique query.
|
||||
// Build unique query which return a single duplicate value.
|
||||
$query = \Drupal::database()->select('webform_submission', 'ws');
|
||||
$query->leftJoin('webform_submission_data', 'wsd', 'ws.sid = wsd.sid');
|
||||
$query->fields('ws', ['sid']);
|
||||
$query->fields('wsd', ['value']);
|
||||
$query->condition('wsd.webform_id', $webform->id());
|
||||
$query->condition('wsd.name', $name);
|
||||
$query->condition('wsd.value', $value);
|
||||
$query->condition('wsd.value', (array) $value, 'IN');
|
||||
// Unique user condition.
|
||||
if (!empty($element['#unique_user'])) {
|
||||
$query->condition('ws.uid', $webform_submission->getOwnerId());
|
||||
|
@ -1879,24 +1890,31 @@ class WebformElementBase extends PluginBase implements WebformElementInterface {
|
|||
if ($sid = $webform_submission->id()) {
|
||||
$query->condition('ws.sid', $sid, '<>');
|
||||
}
|
||||
// Using range() is more efficient than using countQuery() for data checks.
|
||||
// Get single duplicate value.
|
||||
$query->range(0, 1);
|
||||
$count = $query->execute()->fetchField();
|
||||
$duplicate_value = $query->execute()->fetchField();
|
||||
|
||||
if ($count) {
|
||||
if (isset($element['#unique_error'])) {
|
||||
$form_state->setError($element, $element['#unique_error']);
|
||||
}
|
||||
elseif (isset($element['#title'])) {
|
||||
$t_args = [
|
||||
'%name' => empty($element['#title']) ? $element['#parents'][0] : $element['#title'],
|
||||
'%value' => $value,
|
||||
];
|
||||
$form_state->setError($element, t('The value %value has already been submitted once for the %name element. You may have already submitted this webform, or you need to use a different value.', $t_args));
|
||||
}
|
||||
else {
|
||||
$form_state->setError($element);
|
||||
// Skip NULL or empty string value.
|
||||
if ($duplicate_value === FALSE || $duplicate_value === '') {
|
||||
return;
|
||||
}
|
||||
|
||||
if (isset($element['#unique_error'])) {
|
||||
$form_state->setError($element, $element['#unique_error']);
|
||||
}
|
||||
elseif (isset($element['#title'])) {
|
||||
// Get #options display value.
|
||||
if (isset($element['#options'])) {
|
||||
$duplicate_value = WebformOptionsHelper::getOptionText($duplicate_value, $element['#options'], TRUE);
|
||||
}
|
||||
$t_args = [
|
||||
'%name' => empty($element['#title']) ? $element['#parents'][0] : $element['#title'],
|
||||
'%value' => $duplicate_value,
|
||||
];
|
||||
$form_state->setError($element, t('The value %value has already been submitted once for the %name element. You may have already submitted this webform, or you need to use a different value.', $t_args));
|
||||
}
|
||||
else {
|
||||
$form_state->setError($element);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2034,8 +2052,6 @@ class WebformElementBase extends PluginBase implements WebformElementInterface {
|
|||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* @see \Drupal\webform\Entity\Webform::getElementsSelectorOptions
|
||||
*/
|
||||
public function getElementSelectorOptions(array $element) {
|
||||
if ($this->hasMultipleValues($element) && $this->hasMultipleWrapper()) {
|
||||
|
@ -2057,6 +2073,13 @@ class WebformElementBase extends PluginBase implements WebformElementInterface {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getElementSelectorSourceValues(array $element) {
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get an element's (sub)inputs selectors as options.
|
||||
*
|
||||
|
@ -2197,7 +2220,7 @@ class WebformElementBase extends PluginBase implements WebformElementInterface {
|
|||
$form['element_description']['help'] = [
|
||||
'#type' => 'details',
|
||||
'#title' => $this->t('Help'),
|
||||
'#description' => $this->t("Displays a help tooltip after the element's title"),
|
||||
'#description' => $this->t("Displays a help tooltip after the element's title."),
|
||||
'#states' => [
|
||||
'invisible' => [
|
||||
[':input[name="properties[title_display]"]' => ['value' => 'invisible']],
|
||||
|
@ -2532,6 +2555,7 @@ class WebformElementBase extends PluginBase implements WebformElementInterface {
|
|||
'#type' => 'webform_element_states',
|
||||
'#state_options' => $this->getElementStateOptions(),
|
||||
'#selector_options' => $webform->getElementsSelectorOptions(),
|
||||
'#selector_sources' => $webform->getElementsSelectorSourceValues(),
|
||||
'#disabled_message' => TRUE,
|
||||
];
|
||||
$form['conditional_logic']['states_clear'] = [
|
||||
|
@ -2900,6 +2924,18 @@ class WebformElementBase extends PluginBase implements WebformElementInterface {
|
|||
],
|
||||
],
|
||||
];
|
||||
$form['display']['format_attributes'] = [
|
||||
'#type' => 'details',
|
||||
'#title' => $this->t('Display wrapper attributes'),
|
||||
];
|
||||
$form['display']['format_attributes']['format_attributes'] = [
|
||||
'#type' => 'webform_element_attributes',
|
||||
'#title' => $this->t('Display'),
|
||||
'#class__description' => $this->t("Apply classes to the element's display wrapper. Select 'custom…' to enter custom classes."),
|
||||
'#style__description' => $this->t("Apply custom styles to the element's display wrapper."),
|
||||
'#attributes__description' => $this->t("Enter additional attributes to be added to the element's display wrapper."),
|
||||
'#classes' => $this->configFactory->get('webform.settings')->get('element.wrapper_classes'),
|
||||
];
|
||||
|
||||
/* Administration */
|
||||
|
||||
|
|
|
@ -87,7 +87,7 @@ interface WebformElementInterface extends PluginInspectionInterface, PluginFormI
|
|||
* Get the URL for the element's API documentation.
|
||||
*
|
||||
* @return \Drupal\Core\Url|null
|
||||
* The the URL for the element's API documentation.
|
||||
* The URL for the element's API documentation.
|
||||
*/
|
||||
public function getPluginApiUrl();
|
||||
|
||||
|
@ -744,9 +744,24 @@ interface WebformElementInterface extends PluginInspectionInterface, PluginFormI
|
|||
*
|
||||
* @return array
|
||||
* An array of element selectors.
|
||||
*
|
||||
* @see \Drupal\webform\Entity\Webform::getElementsSelectorSourceOption
|
||||
*/
|
||||
public function getElementSelectorOptions(array $element);
|
||||
|
||||
/**
|
||||
* Get an element's selectors source values.
|
||||
*
|
||||
* @param array $element
|
||||
* An element.
|
||||
*
|
||||
* @return array
|
||||
* An array of element selectors source values.
|
||||
*
|
||||
* @see \Drupal\webform\Entity\Webform::getElementsSelectorSourceValues
|
||||
*/
|
||||
public function getElementSelectorSourceValues(array $element);
|
||||
|
||||
/**
|
||||
* Get an element's (sub)input selector value.
|
||||
*
|
||||
|
|
|
@ -114,7 +114,9 @@ abstract class TabularBaseWebformExporter extends WebformExporterBase {
|
|||
case 'changed':
|
||||
case 'timestamp':
|
||||
if (!empty($webform_submission->$field_name->value)) {
|
||||
$record[] = date('Y-m-d H:i:s', $webform_submission->$field_name->value);
|
||||
/** @var \Drupal\Core\Datetime\DateFormatterInterface $date_formatter */
|
||||
$date_formatter = \Drupal::service('date.formatter');
|
||||
$record[] = $date_formatter->format($webform_submission->$field_name->value, 'custom', 'Y-m-d H:i:s');
|
||||
}
|
||||
else {
|
||||
$record[] = '';
|
||||
|
|
|
@ -226,7 +226,7 @@ class ActionWebformHandler extends WebformHandlerBase {
|
|||
|
||||
$this->tokenManager->elementValidate($form);
|
||||
|
||||
return $this->setSettingsParentsRecursively($form);
|
||||
return $this->setSettingsParents($form);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -301,14 +301,14 @@ class ActionWebformHandler extends WebformHandlerBase {
|
|||
// Append notes.
|
||||
if ($this->configuration['notes']) {
|
||||
$notes = rtrim($webform_submission->getNotes());
|
||||
$notes .= ($notes ? PHP_EOL . PHP_EOL : '') . $this->tokenManager->replace($this->configuration['notes'], $webform_submission);
|
||||
$notes .= ($notes ? PHP_EOL . PHP_EOL : '') . $this->tokenManager->replaceNoRenderContext($this->configuration['notes'], $webform_submission);
|
||||
$webform_submission->setNotes($notes);
|
||||
}
|
||||
|
||||
// Set data.
|
||||
if ($this->configuration['data']) {
|
||||
$data = Yaml::decode($this->configuration['data']);
|
||||
$data = $this->tokenManager->replace($data, $webform_submission);
|
||||
$data = $this->tokenManager->replaceNoRenderContext($data, $webform_submission);
|
||||
foreach ($data as $key => $value) {
|
||||
$webform_submission->setElementData($key, $value);
|
||||
}
|
||||
|
@ -317,7 +317,7 @@ class ActionWebformHandler extends WebformHandlerBase {
|
|||
// Display message.
|
||||
if ($this->configuration['message']) {
|
||||
$message = WebformHtmlEditor::checkMarkup(
|
||||
$this->tokenManager->replace($this->configuration['message'], $webform_submission)
|
||||
$this->tokenManager->replaceNoRenderContext($this->configuration['message'], $webform_submission)
|
||||
);
|
||||
$message_type = $this->configuration['message_type'];
|
||||
$this->messenger()->addMessage(\Drupal::service('renderer')->renderPlain($message), $message_type);
|
||||
|
|
|
@ -23,6 +23,7 @@ use Drupal\webform\Plugin\WebformElementManagerInterface;
|
|||
use Drupal\webform\Plugin\WebformHandlerBase;
|
||||
use Drupal\webform\Plugin\WebformHandlerMessageInterface;
|
||||
use Drupal\webform\Twig\TwigExtension;
|
||||
use Drupal\webform\Utility\Mail;
|
||||
use Drupal\webform\Utility\WebformElementHelper;
|
||||
use Drupal\webform\Utility\WebformOptionsHelper;
|
||||
use Drupal\webform\WebformSubmissionConditionsValidatorInterface;
|
||||
|
@ -511,7 +512,6 @@ class EmailWebformHandler extends WebformHandlerBase implements WebformHandlerMe
|
|||
'#title' => $this->t('Body'),
|
||||
'#options' => $body_options,
|
||||
'#required' => TRUE,
|
||||
'#parents' => ['settings', 'body'],
|
||||
'#default_value' => $body_select_default_value,
|
||||
];
|
||||
foreach ($body_default_values as $format => $default_value) {
|
||||
|
@ -530,7 +530,6 @@ class EmailWebformHandler extends WebformHandlerBase implements WebformHandlerMe
|
|||
$form['message']['body_custom_' . $format] += [
|
||||
'#title' => $this->t('Body custom value (@format)', ['@label' => $format]),
|
||||
'#title_display' => 'hidden',
|
||||
'#parents' => ['settings', 'body_custom_' . $format],
|
||||
'#default_value' => $body_custom_default_values[$format],
|
||||
'#states' => [
|
||||
'visible' => [
|
||||
|
@ -543,6 +542,9 @@ class EmailWebformHandler extends WebformHandlerBase implements WebformHandlerMe
|
|||
],
|
||||
],
|
||||
];
|
||||
// Must set #parents because body_custom_* is not a configuration value.
|
||||
// @see \Drupal\webform\Plugin\WebformHandler\EmailWebformHandler::validateConfigurationForm
|
||||
$form['message']['body_custom_' . $format]['#parents'] = ['settings', 'body_custom_' . $format];
|
||||
|
||||
// Default body.
|
||||
$form['message']['body_default_' . $format] = [
|
||||
|
@ -566,7 +568,6 @@ class EmailWebformHandler extends WebformHandlerBase implements WebformHandlerMe
|
|||
'#mode' => 'twig',
|
||||
'#title' => $this->t('Body custom value (Twig)'),
|
||||
'#title_display' => 'hidden',
|
||||
'#parents' => ['settings', 'body_custom_twig'],
|
||||
'#default_value' => $body_custom_default_values['twig'],
|
||||
'#access' => $has_edit_twig_access,
|
||||
'#states' => [
|
||||
|
@ -577,6 +578,9 @@ class EmailWebformHandler extends WebformHandlerBase implements WebformHandlerMe
|
|||
':input[name="settings[body]"]' => ['value' => 'twig'],
|
||||
],
|
||||
],
|
||||
// Must set #parents because body_custom_twig is not a configuration value.
|
||||
// @see \Drupal\webform\Plugin\WebformHandler\EmailWebformHandler::validateConfigurationForm
|
||||
'#parents' => ['settings', 'body_custom_twig'],
|
||||
];
|
||||
$form['message']['body_custom_twig_help'] = TwigExtension::buildTwigHelp() + [
|
||||
'#access' => $has_edit_twig_access,
|
||||
|
@ -603,7 +607,6 @@ class EmailWebformHandler extends WebformHandlerBase implements WebformHandlerMe
|
|||
'#type' => 'webform_excluded_elements',
|
||||
'#webform_id' => $this->webform->id(),
|
||||
'#default_value' => $this->configuration['excluded_elements'],
|
||||
'#parents' => ['settings', 'excluded_elements'],
|
||||
];
|
||||
$form['elements']['ignore_access'] = [
|
||||
'#type' => 'checkbox',
|
||||
|
@ -611,21 +614,18 @@ class EmailWebformHandler extends WebformHandlerBase implements WebformHandlerMe
|
|||
'#description' => $this->t('If checked, access controls for included element will be ignored.'),
|
||||
'#return_value' => TRUE,
|
||||
'#default_value' => $this->configuration['ignore_access'],
|
||||
'#parents' => ['settings', 'ignore_access'],
|
||||
];
|
||||
$form['elements']['exclude_empty'] = [
|
||||
'#type' => 'checkbox',
|
||||
'#title' => t('Exclude empty elements'),
|
||||
'#return_value' => TRUE,
|
||||
'#default_value' => $this->configuration['exclude_empty'],
|
||||
'#parents' => ['settings', 'exclude_empty'],
|
||||
];
|
||||
$form['elements']['exclude_empty_checkbox'] = [
|
||||
'#type' => 'checkbox',
|
||||
'#title' => t('Exclude unselected checkboxes'),
|
||||
'#return_value' => TRUE,
|
||||
'#default_value' => $this->configuration['exclude_empty_checkbox'],
|
||||
'#parents' => ['settings', 'exclude_empty_checkbox'],
|
||||
];
|
||||
$elements = $this->webform->getElementsInitializedFlattenedAndHasValue();
|
||||
foreach ($elements as $key => $element) {
|
||||
|
@ -660,7 +660,6 @@ class EmailWebformHandler extends WebformHandlerBase implements WebformHandlerMe
|
|||
WebformSubmissionInterface::STATE_DELETED => $this->t('…when submission is <b>deleted</b>.'),
|
||||
],
|
||||
'#access' => $results_disabled ? FALSE : TRUE,
|
||||
'#parents' => ['settings', 'states'],
|
||||
'#default_value' => $results_disabled ? [WebformSubmissionInterface::STATE_COMPLETED] : $this->configuration['states'],
|
||||
];
|
||||
$form['additional']['states_message'] = [
|
||||
|
@ -688,7 +687,6 @@ class EmailWebformHandler extends WebformHandlerBase implements WebformHandlerMe
|
|||
'#title' => $this->t('Send email as HTML'),
|
||||
'#return_value' => TRUE,
|
||||
'#access' => $this->supportsHtml(),
|
||||
'#parents' => ['settings', 'html'],
|
||||
'#default_value' => $this->configuration['html'],
|
||||
];
|
||||
// Settings: Attachments.
|
||||
|
@ -697,7 +695,6 @@ class EmailWebformHandler extends WebformHandlerBase implements WebformHandlerMe
|
|||
'#title' => $this->t('Include files as attachments'),
|
||||
'#return_value' => TRUE,
|
||||
'#access' => $this->supportsAttachments(),
|
||||
'#parents' => ['settings', 'attachments'],
|
||||
'#default_value' => $this->configuration['attachments'],
|
||||
];
|
||||
|
||||
|
@ -707,7 +704,6 @@ class EmailWebformHandler extends WebformHandlerBase implements WebformHandlerMe
|
|||
'#title' => $this->t('Theme to render this email'),
|
||||
'#description' => $this->t('Select the theme that will be used to render this email.'),
|
||||
'#options' => $this->themeManager->getThemeNames(),
|
||||
'#parents' => ['settings', 'theme_name'],
|
||||
'#default_value' => $this->configuration['theme_name'],
|
||||
];
|
||||
|
||||
|
@ -721,7 +717,6 @@ class EmailWebformHandler extends WebformHandlerBase implements WebformHandlerMe
|
|||
'#title' => $this->t('Enable debugging'),
|
||||
'#description' => $this->t('If checked, sent emails will be displayed onscreen to all users.'),
|
||||
'#return_value' => TRUE,
|
||||
'#parents' => ['settings', 'debug'],
|
||||
'#default_value' => $this->configuration['debug'],
|
||||
];
|
||||
|
||||
|
@ -731,7 +726,7 @@ class EmailWebformHandler extends WebformHandlerBase implements WebformHandlerMe
|
|||
|
||||
$this->tokenManager->elementValidate($form, $token_types);
|
||||
|
||||
return $form;
|
||||
return $this->setSettingsParents($form);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -866,7 +861,7 @@ class EmailWebformHandler extends WebformHandlerBase implements WebformHandlerMe
|
|||
$token_options['clear'] = (strpos($configuration_key, '_mail') !== FALSE) ? TRUE : FALSE;
|
||||
|
||||
// Get replace token values.
|
||||
$token_value = $this->tokenManager->replace($configuration_value, $webform_submission, $token_data, $token_options);
|
||||
$token_value = $this->tokenManager->replaceNoRenderContext($configuration_value, $webform_submission, $token_data, $token_options);
|
||||
|
||||
// Decode entities for all message values except the HTML message body.
|
||||
if (!empty($token_value) && is_string($token_value) && !($token_options['html'] && $configuration_key === 'body')) {
|
||||
|
@ -989,7 +984,7 @@ class EmailWebformHandler extends WebformHandlerBase implements WebformHandlerMe
|
|||
if ($this->moduleHandler->moduleExists('webform_access')) {
|
||||
$token_data['webform_access'] = $webform_submission;
|
||||
}
|
||||
$emails = $this->tokenManager->replace($emails, $webform_submission, $token_data);
|
||||
$emails = $this->tokenManager->replaceNoRenderContext($emails, $webform_submission, $token_data);
|
||||
}
|
||||
|
||||
// Resplit emails to make sure that emails are unique.
|
||||
|
@ -1069,7 +1064,7 @@ class EmailWebformHandler extends WebformHandlerBase implements WebformHandlerMe
|
|||
$message['from_name'] = preg_replace('/[<>]/', '', $message['from_name']);
|
||||
|
||||
if (!empty($message['from_name'])) {
|
||||
$from = $message['from_name'] . ' <' . $from . '>';
|
||||
$from = Mail::formatDisplayName($message['from_name']) . ' <' . $from . '>';
|
||||
}
|
||||
|
||||
$current_langcode = $this->languageManager->getCurrentLanguage()->getId();
|
||||
|
@ -1118,22 +1113,29 @@ class EmailWebformHandler extends WebformHandlerBase implements WebformHandlerMe
|
|||
|
||||
$result = $this->mailManager->mail('webform', $key, $to, $current_langcode, $message, $from);
|
||||
|
||||
// Log message in Drupal's log.
|
||||
$context = [
|
||||
'@form' => $this->getWebform()->label(),
|
||||
'@title' => $this->label(),
|
||||
'link' => $this->getWebform()->toLink($this->t('Edit'), 'handlers')->toString(),
|
||||
];
|
||||
$this->getLogger()->notice('@form webform sent @title email.', $context);
|
||||
|
||||
// Log message in Webform's submission log.
|
||||
$t_args = [
|
||||
'@from_name' => $message['from_name'],
|
||||
'@from_mail' => $message['from_mail'],
|
||||
'@to_mail' => $message['to_mail'],
|
||||
'@subject' => $message['subject'],
|
||||
];
|
||||
$this->log($webform_submission, 'sent email', $this->t("'@subject' sent to '@to_mail' from '@from_name' [@from_mail]'.", $t_args));
|
||||
if ($webform_submission->getWebform()->hasSubmissionLog()) {
|
||||
// Log detailed message to the 'webform_submission' log.
|
||||
$context = [
|
||||
'@from_name' => $message['from_name'],
|
||||
'@from_mail' => $message['from_mail'],
|
||||
'@to_mail' => $message['to_mail'],
|
||||
'@subject' => $message['subject'],
|
||||
'link' => $webform_submission->toLink($this->t('View'))->toString(),
|
||||
'webform_submission' => $webform_submission,
|
||||
'handler_id' => $this->getHandlerId(),
|
||||
'operation' => 'sent email',
|
||||
];
|
||||
$this->getLogger('webform_submission')->notice("'@subject' sent to '@to_mail' from '@from_name' [@from_mail]'.", $context);
|
||||
}
|
||||
else {
|
||||
// Log general message to the 'webform' log.
|
||||
$context = [
|
||||
'@form' => $this->getWebform()->label(),
|
||||
'@title' => $this->label(),
|
||||
'link' => $this->getWebform()->toLink($this->t('Edit'), 'handlers')->toString(),
|
||||
];
|
||||
$this->getLogger('webform')->notice('@form webform sent @title email.', $context);
|
||||
}
|
||||
|
||||
// Debug by displaying send email onscreen.
|
||||
if ($this->configuration['debug']) {
|
||||
|
@ -1431,7 +1433,6 @@ class EmailWebformHandler extends WebformHandlerBase implements WebformHandlerMe
|
|||
'#other__type' => ($element_type == 'mail') ? 'webform_email_multiple' : 'textfield',
|
||||
'#other__allow_tokens' => TRUE,
|
||||
'#required' => $required,
|
||||
'#parents' => ['settings', $name],
|
||||
'#default_value' => $this->configuration[$name],
|
||||
];
|
||||
|
||||
|
@ -1488,7 +1489,7 @@ class EmailWebformHandler extends WebformHandlerBase implements WebformHandlerMe
|
|||
'#value' => $this->t('Update'),
|
||||
'#name' => $element_name . '_update_button',
|
||||
'#validate' => [],
|
||||
'#limit_validation_errors' => [$element[$name]['#parents']],
|
||||
'#limit_validation_errors' => [['settings', $name]],
|
||||
'#submit' => [[get_called_class(), 'rebuildCallback']],
|
||||
'#ajax' => [
|
||||
'callback' => [get_called_class(), 'ajaxCallback'],
|
||||
|
@ -1539,7 +1540,6 @@ class EmailWebformHandler extends WebformHandlerBase implements WebformHandlerMe
|
|||
'#description' => $this->t('The selected element has multiple options. You may enter email addresses for each choice. When that choice is selected, an email will be sent to the corresponding addresses. If a field is left blank, no email will be sent for that option. You may use tokens.') . '<br /><br />',
|
||||
'#description_display' => 'before',
|
||||
'#required' => TRUE,
|
||||
'#parents' => ['settings', $options_name],
|
||||
'#default_value' => WebformOptionsHelper::decodeConfig($this->configuration[$options_name]),
|
||||
|
||||
'#source' => $mapping_options,
|
||||
|
@ -1556,7 +1556,6 @@ class EmailWebformHandler extends WebformHandlerBase implements WebformHandlerMe
|
|||
$element[$options_name] = [
|
||||
'#type' => 'value',
|
||||
'#value' => [],
|
||||
'#parents' => ['settings', $options_name],
|
||||
];
|
||||
}
|
||||
|
||||
|
|
|
@ -230,7 +230,6 @@ class RemotePostWebformHandler extends WebformHandlerBase {
|
|||
'#title' => $this->t('@title URL', $t_args),
|
||||
'#description' => $this->t('The full URL to POST to when an existing webform submission is @state. (e.g. @url)', $t_args),
|
||||
'#required' => ($state === WebformSubmissionInterface::STATE_COMPLETED),
|
||||
'#parents' => ['settings', $state_url],
|
||||
'#default_value' => $this->configuration[$state_url],
|
||||
];
|
||||
$form[$state][$state_custom_data] = [
|
||||
|
@ -238,7 +237,6 @@ class RemotePostWebformHandler extends WebformHandlerBase {
|
|||
'#mode' => 'yaml',
|
||||
'#title' => $this->t('@title custom data', $t_args),
|
||||
'#description' => $this->t('Enter custom data that will be included when a webform submission is @state.', $t_args),
|
||||
'#parents' => ['settings', $state_custom_data],
|
||||
'#states' => ['visible' => [':input[name="settings[' . $state_url . ']"]' => ['filled' => TRUE]]],
|
||||
'#default_value' => $this->configuration[$state_custom_data],
|
||||
];
|
||||
|
@ -266,18 +264,16 @@ class RemotePostWebformHandler extends WebformHandlerBase {
|
|||
'PUT' => 'PUT',
|
||||
'GET' => 'GET',
|
||||
],
|
||||
'#parents' => ['settings', 'method'],
|
||||
'#default_value' => $this->configuration['method'],
|
||||
];
|
||||
$form['additional']['type'] = [
|
||||
'#type' => 'select',
|
||||
'#title' => $this->t('Post type'),
|
||||
'#description' => $this->t('Use x-www-form-urlencoded if unsure, as it is the default format for HTML webforms. You also have the option to post data in <a href="http://www.json.org/" target="_blank">JSON</a> format.'),
|
||||
'#description' => $this->t('Use x-www-form-urlencoded if unsure, as it is the default format for HTML webforms. You also have the option to post data in <a href="http://www.json.org/">JSON</a> format.'),
|
||||
'#options' => [
|
||||
'x-www-form-urlencoded' => $this->t('x-www-form-urlencoded'),
|
||||
'json' => $this->t('JSON'),
|
||||
],
|
||||
'#parents' => ['settings', 'type'],
|
||||
'#states' => [
|
||||
'!visible' => [':input[name="settings[method]"]' => ['value' => 'GET']],
|
||||
'!required' => [':input[name="settings[method]"]' => ['value' => 'GET']],
|
||||
|
@ -289,22 +285,19 @@ class RemotePostWebformHandler extends WebformHandlerBase {
|
|||
'#mode' => 'yaml',
|
||||
'#title' => $this->t('Custom data'),
|
||||
'#description' => $this->t('Enter custom data that will be included in all remote post requests.'),
|
||||
'#parents' => ['settings', 'custom_data'],
|
||||
'#default_value' => $this->configuration['custom_data'],
|
||||
];
|
||||
$form['additional']['custom_options'] = [
|
||||
'#type' => 'webform_codemirror',
|
||||
'#mode' => 'yaml',
|
||||
'#title' => $this->t('Custom options'),
|
||||
'#description' => $this->t('Enter custom <a href=":href">request options</a> that will be used by the Guzzle HTTP client. Request options can included custom headers.', [':href' => 'http://docs.guzzlephp.org/en/stable/request-options.html']),
|
||||
'#parents' => ['settings', 'custom_options'],
|
||||
'#description' => $this->t('Enter custom <a href=":href">request options</a> that will be used by the Guzzle HTTP client. Request options can include custom headers.', [':href' => 'http://docs.guzzlephp.org/en/stable/request-options.html']),
|
||||
'#default_value' => $this->configuration['custom_options'],
|
||||
];
|
||||
$form['additional']['message'] = [
|
||||
'#type' => 'webform_html_editor',
|
||||
'#title' => $this->t('Custom error response message'),
|
||||
'#description' => $this->t('This message is displayed when the response status code is not 2xx'),
|
||||
'#parents' => ['settings', 'message'],
|
||||
'#default_value' => $this->configuration['message'],
|
||||
];
|
||||
$form['additional']['messages_token'] = [
|
||||
|
@ -317,6 +310,7 @@ class RemotePostWebformHandler extends WebformHandlerBase {
|
|||
'#title' => $this->t('Custom error response messages'),
|
||||
'#description' => $this->t('Enter custom response messages for specific status codes.') . '<br/>' . $this->t('Defaults to: %value', ['%value' => $this->messageManager->render(WebformMessageManagerInterface::SUBMISSION_EXCEPTION_MESSAGE)]),
|
||||
'#empty_items' => 0,
|
||||
'#no_items_message' => $this->t('No error response messages entered. Please add messages below.'),
|
||||
'#add' => FALSE,
|
||||
'#element' => [
|
||||
'code' => [
|
||||
|
@ -340,7 +334,6 @@ class RemotePostWebformHandler extends WebformHandlerBase {
|
|||
'#title' => $this->t('Response message'),
|
||||
],
|
||||
],
|
||||
'#parents' => ['settings', 'messages'],
|
||||
'#default_value' => $this->configuration['messages'],
|
||||
];
|
||||
|
||||
|
@ -354,7 +347,6 @@ class RemotePostWebformHandler extends WebformHandlerBase {
|
|||
'#title' => $this->t('Enable debugging'),
|
||||
'#description' => $this->t('If checked, posted submissions will be displayed onscreen to all users.'),
|
||||
'#return_value' => TRUE,
|
||||
'#parents' => ['settings', 'debug'],
|
||||
'#default_value' => $this->configuration['debug'],
|
||||
];
|
||||
|
||||
|
@ -380,13 +372,12 @@ class RemotePostWebformHandler extends WebformHandlerBase {
|
|||
'#title_display' => 'invisible',
|
||||
'#webform_id' => $webform->id(),
|
||||
'#required' => TRUE,
|
||||
'#parents' => ['settings', 'excluded_data'],
|
||||
'#default_value' => $this->configuration['excluded_data'],
|
||||
];
|
||||
|
||||
$this->tokenManager->elementValidate($form);
|
||||
|
||||
return $form;
|
||||
return $this->setSettingsParents($form);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -436,12 +427,13 @@ class RemotePostWebformHandler extends WebformHandlerBase {
|
|||
$this->messageManager->setWebformSubmission($webform_submission);
|
||||
|
||||
$request_url = $this->configuration[$state . '_url'];
|
||||
$request_url = $this->tokenManager->replace($request_url, $webform_submission);
|
||||
$request_method = (!empty($this->configuration['method'])) ? $this->configuration['method'] : 'POST';
|
||||
$request_type = ($request_method !== 'GET') ? $this->configuration['type'] : NULL;
|
||||
|
||||
// Get request options with tokens replaced.
|
||||
$request_options = (!empty($this->configuration['custom_options'])) ? Yaml::decode($this->configuration['custom_options']) : [];
|
||||
$request_options = $this->tokenManager->replace($request_options, $webform_submission);
|
||||
$request_options = $this->tokenManager->replaceNoRenderContext($request_options, $webform_submission);
|
||||
|
||||
try {
|
||||
if ($request_method === 'GET') {
|
||||
|
@ -485,7 +477,7 @@ class RemotePostWebformHandler extends WebformHandlerBase {
|
|||
if ($submission_has_token) {
|
||||
$response_data = $this->getResponseData($response);
|
||||
$token_data = ['webform_handler' => [$this->getHandlerId() => [$state => $response_data]]];
|
||||
$submission_data = $this->tokenManager->replace($submission_data, $webform_submission, $token_data);
|
||||
$submission_data = $this->tokenManager->replaceNoRenderContext($submission_data, $webform_submission, $token_data);
|
||||
$webform_submission->setData($submission_data);
|
||||
// Resave changes to the submission data without invoking any hooks
|
||||
// or handlers.
|
||||
|
@ -567,7 +559,7 @@ class RemotePostWebformHandler extends WebformHandlerBase {
|
|||
}
|
||||
|
||||
// Replace tokens.
|
||||
$data = $this->tokenManager->replace($data, $webform_submission);
|
||||
$data = $this->tokenManager->replaceNoRenderContext($data, $webform_submission);
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
@ -868,7 +860,7 @@ class RemotePostWebformHandler extends WebformHandlerBase {
|
|||
],
|
||||
];
|
||||
$build_message = [
|
||||
'#markup' => $this->tokenManager->replace($custom_response_message, $this->getWebform(), $token_data),
|
||||
'#markup' => $this->tokenManager->replaceNoRenderContext($custom_response_message, $this->getWebform(), $token_data),
|
||||
];
|
||||
$this->messenger()->addError(\Drupal::service('renderer')->renderPlain($build_message));
|
||||
}
|
||||
|
|
|
@ -181,7 +181,6 @@ class SettingsWebformHandler extends WebformHandlerBase {
|
|||
'#title' => $this->t('Custom settings (YAML)'),
|
||||
'#description' => $this->t('Enter the setting name and value as YAML.'),
|
||||
'#default_value' => $custom_settings,
|
||||
'#parents' => ['settings', 'custom'],
|
||||
];
|
||||
|
||||
// Custom settings definitions.
|
||||
|
@ -228,7 +227,7 @@ class SettingsWebformHandler extends WebformHandlerBase {
|
|||
|
||||
$this->tokenManager->elementValidate($form);
|
||||
|
||||
return $this->setSettingsParentsRecursively($form);
|
||||
return $this->setSettingsParents($form);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -394,7 +393,7 @@ class SettingsWebformHandler extends WebformHandlerBase {
|
|||
// Replace token value and cast booleans and integers.
|
||||
$type = $settings_definitions[$name]['type'];
|
||||
if (in_array($type, ['boolean', 'integer'])) {
|
||||
$value = $this->tokenManager->replace($value, $webform_submission);
|
||||
$value = $this->tokenManager->replaceNoRenderContext($value, $webform_submission);
|
||||
settype($value, $type);
|
||||
$settings_override[$name] = $value;
|
||||
}
|
||||
|
|
|
@ -599,7 +599,24 @@ abstract class WebformHandlerBase extends PluginBase implements WebformHandlerIn
|
|||
*
|
||||
* This helper method looks looks for the handler default configuration keys
|
||||
* within a form and set a matching element's #parents property to
|
||||
* ['settings', '{element_kye}']
|
||||
* ['settings', '{element_key}']
|
||||
*
|
||||
* @param array $elements
|
||||
* An array of form elements.
|
||||
*
|
||||
* @return array
|
||||
* Form element with #parents set.
|
||||
*/
|
||||
protected function setSettingsParents(array &$elements) {
|
||||
return $this->setSettingsParentsRecursively($elements);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set configuration settings parents.
|
||||
*
|
||||
* This helper method looks looks for the handler default configuration keys
|
||||
* within a form and set a matching element's #parents property to
|
||||
* ['settings', '{element_key}']
|
||||
*
|
||||
* @param array $elements
|
||||
* An array of form elements.
|
||||
|
@ -621,7 +638,14 @@ abstract class WebformHandlerBase extends PluginBase implements WebformHandlerIn
|
|||
continue;
|
||||
}
|
||||
|
||||
if (array_key_exists($element_key, $default_configuration) && isset($element['#type'])) {
|
||||
// Only set #parents when #element has…
|
||||
// - Default configuration.
|
||||
// - Is an input.
|
||||
// - #default_value or #value (aka input).
|
||||
// - Not a container with children.
|
||||
if (array_key_exists($element_key, $default_configuration)
|
||||
&& isset($element['#type'])
|
||||
&& !WebformElementHelper::hasChildren($element)) {
|
||||
$element['#parents'] = ['settings', $element_key];
|
||||
}
|
||||
else {
|
||||
|
@ -636,13 +660,16 @@ abstract class WebformHandlerBase extends PluginBase implements WebformHandlerIn
|
|||
/****************************************************************************/
|
||||
|
||||
/**
|
||||
* Get webform logger.
|
||||
* Get webform or webform_submission logger.
|
||||
*
|
||||
* @param string $channel
|
||||
* The logger channel. Defaults to 'webform'.
|
||||
*
|
||||
* @return \Drupal\Core\Logger\LoggerChannelInterface
|
||||
* Webform logger
|
||||
*/
|
||||
protected function getLogger() {
|
||||
return $this->loggerFactory->get('webform');
|
||||
protected function getLogger($channel = 'webform') {
|
||||
return $this->loggerFactory->get($channel);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -656,6 +683,18 @@ abstract class WebformHandlerBase extends PluginBase implements WebformHandlerIn
|
|||
* The message to be logged.
|
||||
* @param array $data
|
||||
* The data to be saved with log record.
|
||||
*
|
||||
* @deprecated Instead call the 'webform_submission' logger channel directly.
|
||||
*
|
||||
* $message = 'Some message with an %argument.'
|
||||
* $context = [
|
||||
* '%argument' => 'Some value'
|
||||
* 'link' => $webform_submission->toLink($this->t('Edit'), 'edit-form')->toString(),
|
||||
* 'webform_submission' => $webform_submission,
|
||||
* 'handler_id' => NULL,
|
||||
* 'data' => [],
|
||||
* ];
|
||||
* \Drupal::logger('webform_submission')->notice($message, $context);
|
||||
*/
|
||||
protected function log(WebformSubmissionInterface $webform_submission, $operation, $message = '', array $data = []) {
|
||||
if ($webform_submission->getWebform()->hasSubmissionLog()) {
|
||||
|
|
|
@ -148,16 +148,14 @@ class QueryStringWebformSourceEntity extends PluginBase implements WebformSource
|
|||
// Check that the webform is referenced by the source entity.
|
||||
if (!$webform->getSetting('form_prepopulate_source_entity')) {
|
||||
// Get source entity's webform field.
|
||||
$webform_field_name = $this->webformEntityReferenceManager->getFieldName($source_entity);
|
||||
if (!$webform_field_name) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Check that source entity's reference webform is the
|
||||
// current webform.
|
||||
foreach ($source_entity->$webform_field_name as $item) {
|
||||
if ($item->target_id === $webform->id()) {
|
||||
return WebformSourceEntityManager::getMainSourceEntity($source_entity);
|
||||
$webform_field_names = $this->webformEntityReferenceManager->getFieldNames($source_entity);
|
||||
foreach ($webform_field_names as $webform_field_name) {
|
||||
// Check that source entity's reference webform is the
|
||||
// current webform.
|
||||
foreach ($source_entity->$webform_field_name as $item) {
|
||||
if ($item->target_id === $webform->id()) {
|
||||
return WebformSourceEntityManager::getMainSourceEntity($source_entity);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -71,7 +71,7 @@ class WebformSourceEntityManager extends DefaultPluginManager implements Webform
|
|||
* @see \Drupal\webform\Plugin\WebformSourceEntity\QueryStringWebformSourceEntity::getSourceEntity
|
||||
*/
|
||||
public static function getMainSourceEntity(EntityInterface $source_entity) {
|
||||
while ($source_entity->getEntityTypeId() === 'paragraph') {
|
||||
while ($source_entity && $source_entity->getEntityTypeId() === 'paragraph') {
|
||||
$source_entity = $source_entity->getParentEntity();
|
||||
}
|
||||
return $source_entity;
|
||||
|
|
|
@ -55,7 +55,7 @@ class WebformAccessEntityJsonApiTest extends WebformTestBase {
|
|||
// Check rest access allowed to webform.
|
||||
$this->drupalGet("jsonapi/webform/webform/$uuid");
|
||||
$this->assertNoRaw('"title":"Forbidden","status":403,"detail":"The current user is not allowed to GET the selected resource. Access to webform configuration is required."');
|
||||
$this->assertRaw('"drupal_internal__id":"contact","title":"Contact"');
|
||||
$this->assertRaw('"title":"Contact",');
|
||||
|
||||
// Allow anonymous role to access webform configuration.
|
||||
$access_rules = $webform->getAccessRules();
|
||||
|
|
|
@ -42,7 +42,7 @@ class WebformAccessEntityRulesTest extends WebformTestBase {
|
|||
/** @var \Drupal\webform\WebformSubmissionInterface[] $submissions */
|
||||
$submissions = array_values(\Drupal::entityTypeManager()->getStorage('webform_submission')->loadByProperties(['webform_id' => 'test_submissions']));
|
||||
|
||||
$account = $this->drupalCreateUser(['access content']);
|
||||
$account = $this->drupalCreateUser(['access content', 'edit webform source']);
|
||||
|
||||
$webform_id = $webform->id();
|
||||
$sid = $submissions[0]->id();
|
||||
|
|
|
@ -63,7 +63,7 @@ class WebformCompositeFormatTest extends WebformTestBase {
|
|||
'Link (Value)' => '<a href="http://example.com">Loremipsum</a>',
|
||||
];
|
||||
foreach ($elements as $label => $value) {
|
||||
$this->assertContains($body, '<b>' . $label . '</b><br />' . $value, new FormattableMarkup('Found @label: @value', ['@label' => $label, '@value' => $value]));
|
||||
$this->assertContains('<b>' . $label . '</b><br />' . $value, $body, new FormattableMarkup('Found @label: @value', ['@label' => $label, '@value' => $value]));
|
||||
}
|
||||
|
||||
// Check composite elements formatted as text.
|
||||
|
@ -133,7 +133,7 @@ Country code: US
|
|||
Language code: en',
|
||||
];
|
||||
foreach ($elements as $value) {
|
||||
$this->assertContains($body, $value, new FormattableMarkup('Found @value', ['@value' => $value]));
|
||||
$this->assertContains($value, $body, new FormattableMarkup('Found @value', ['@value' => $value]));
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
|
@ -160,7 +160,7 @@ Language code: en',
|
|||
'Basic address (Table)' => '<table width="100%" cellspacing="0" cellpadding="5" border="1" class="responsive-enabled" data-striping="1"><thead><tr><th bgcolor="#eee">Address</th><th bgcolor="#eee">Address 2</th><th bgcolor="#eee">City/Town</th><th bgcolor="#eee">State/Province</th><th bgcolor="#eee">ZIP/Postal Code</th><th bgcolor="#eee">Country</th></tr></thead><tbody><tr class="odd"><td>10 Main Street</td><td>10 Main Street</td><td>Springfield</td><td>Alabama</td><td>11111</td><td>Afghanistan</td></tr><tr class="even"><td>10 Main Street</td><td>10 Main Street</td><td>Springfield</td><td>Alabama</td><td>11111</td><td>Afghanistan</td></tr><tr class="odd"><td>10 Main Street</td><td>10 Main Street</td><td>Springfield</td><td>Alabama</td><td>11111</td><td>Afghanistan</td></tr></tbody></table>',
|
||||
];
|
||||
foreach ($elements as $label => $value) {
|
||||
$this->assertContains($body, '<b>' . $label . '</b><br />' . $value, new FormattableMarkup('Found @label: @value', ['@label' => $label, '@value' => $value]));
|
||||
$this->assertContains('<b>' . $label . '</b><br />' . $value, $body, new FormattableMarkup('Found @label: @value', ['@label' => $label, '@value' => $value]));
|
||||
}
|
||||
|
||||
// Check composite elements formatted as text.
|
||||
|
@ -209,7 +209,7 @@ Springfield, Alabama. 11111
|
|||
Afghanistan',
|
||||
];
|
||||
foreach ($elements as $value) {
|
||||
$this->assertContains($body, $value, new FormattableMarkup('Found @value', ['@value' => $value]));
|
||||
$this->assertContains($value, $body, new FormattableMarkup('Found @value', ['@value' => $value]));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -30,6 +30,11 @@ class WebformElementCodeMirrorTest extends WebformElementTestBase {
|
|||
$this->assertRaw('<label for="edit-text-basic">text_basic</label>');
|
||||
$this->assertRaw('<textarea data-drupal-selector="edit-text-basic" class="js-webform-codemirror webform-codemirror text form-textarea resize-vertical" data-webform-codemirror-mode="text/plain" id="edit-text-basic" name="text_basic" rows="5" cols="60">Hello</textarea>');
|
||||
|
||||
// Check Text with no wrap.
|
||||
$this->drupalGet('webform/test_element_codemirror');
|
||||
$this->assertRaw('<label for="edit-text-basic-no-wrap">text_basic_no_wrap</label>');
|
||||
$this->assertRaw('<textarea data-drupal-selector="edit-text-basic-no-wrap" wrap="off" class="js-webform-codemirror webform-codemirror text form-textarea resize-vertical" data-webform-codemirror-mode="text/plain" id="edit-text-basic-no-wrap" name="text_basic_no_wrap" rows="5" cols="60">');
|
||||
|
||||
/**************************************************************************/
|
||||
// code:yaml
|
||||
/**************************************************************************/
|
||||
|
|
|
@ -68,7 +68,7 @@ class WebformElementComputedTest extends WebformElementTestBase {
|
|||
$this->assertRaw('<b class="webform_computed_token_html">xss:</b> <script>alert("XSS");</script><br />');
|
||||
|
||||
// Check token plain text rendering.
|
||||
$this->assertRaw('<div id="test_element_computed_token--webform_computed_token_text" class="webform-element webform-element-type-webform-computed-token js-form-item form-item js-form-type-item form-type-item js-form-item-webform-computed-token-text form-item-webform-computed-token-text">');
|
||||
$this->assertRaw('<div class="webform-element webform-element-type-webform-computed-token js-form-item form-item js-form-type-item form-type-item js-form-item-webform-computed-token-text form-item-webform-computed-token-text" id="test_element_computed_token--webform_computed_token_text">');
|
||||
$this->assertRaw('<label>webform_computed_token_text</label>');
|
||||
$this->assertRaw('simple string: This is a string<br />');
|
||||
$this->assertRaw('complex string : This is a <strong>complex</strong> string, which contains "double" and 'single' quotes with special characters like >, <, ><, and <>.<br />');
|
||||
|
|
|
@ -29,6 +29,9 @@ class WebformElementDateListTest extends WebformElementTestBase {
|
|||
$this->drupalGet('webform/test_element_datelist');
|
||||
$this->assertFieldByName('datelist_default[month]', '8');
|
||||
|
||||
// Check '#date_abbreviate': false.
|
||||
$this->assertRaw('<select data-drupal-selector="edit-datelist-no-abbreviate-month" title="Month" id="edit-datelist-no-abbreviate-month" name="datelist_no_abbreviate[month]" class="form-select"><option value="">Month</option><option value="1">January</option>');
|
||||
|
||||
// Check date year range reverse.
|
||||
$this->drupalGet('webform/test_element_datelist');
|
||||
$this->assertRaw('<select data-drupal-selector="edit-datelist-date-year-range-reverse-year" title="Year" id="edit-datelist-date-year-range-reverse-year" name="datelist_date_year_range_reverse[year]" class="form-select"><option value="" selected="selected">Year</option><option value="2010">2010</option><option value="2009">2009</option><option value="2008">2008</option><option value="2007">2007</option><option value="2006">2006</option><option value="2005">2005</option></select>');
|
||||
|
@ -37,7 +40,7 @@ class WebformElementDateListTest extends WebformElementTestBase {
|
|||
$form = $webform->getSubmissionForm();
|
||||
$this->assert($form['elements']['datelist_default']['#default_value'] instanceof DrupalDateTime, 'datelist_default #default_value instance of \Drupal\Core\Datetime\DrupalDateTime.');
|
||||
|
||||
// Check datelist #max validation.
|
||||
// Check datelist #date_date_max validation.
|
||||
$edit = [
|
||||
'datelist_min_max[year]' => '2010',
|
||||
'datelist_min_max[month]' => '8',
|
||||
|
@ -46,7 +49,7 @@ class WebformElementDateListTest extends WebformElementTestBase {
|
|||
$this->drupalPostForm('webform/test_element_datelist', $edit, t('Submit'));
|
||||
$this->assertRaw('<em class="placeholder">datelist_min_max</em> must be on or before <em class="placeholder">2009-12-31</em>.');
|
||||
|
||||
// Check datelist #min validation.
|
||||
// Check datelist #date_date_min validation.
|
||||
$edit = [
|
||||
'datelist_min_max[year]' => '2006',
|
||||
'datelist_min_max[month]' => '8',
|
||||
|
@ -55,6 +58,26 @@ class WebformElementDateListTest extends WebformElementTestBase {
|
|||
$this->drupalPostForm('webform/test_element_datelist', $edit, t('Submit'));
|
||||
$this->assertRaw('<em class="placeholder">datelist_min_max</em> must be on or after <em class="placeholder">2009-01-01</em>.');
|
||||
|
||||
// Check datelist #date_max validation.
|
||||
$edit = [
|
||||
'datelist_min_max_time[year]' => '2009',
|
||||
'datelist_min_max_time[month]' => '12',
|
||||
'datelist_min_max_time[day]' => '31',
|
||||
'datelist_min_max_time[hour]' => '18',
|
||||
];
|
||||
$this->drupalPostForm('webform/test_element_datelist', $edit, t('Submit'));
|
||||
$this->assertRaw('<em class="placeholder">datelist_min_max_time</em> must be on or before <em class="placeholder">2009-12-31 17:00:00</em>.');
|
||||
|
||||
// Check datelist #date_min validation.
|
||||
$edit = [
|
||||
'datelist_min_max_time[year]' => '2009',
|
||||
'datelist_min_max_time[month]' => '1',
|
||||
'datelist_min_max_time[day]' => '1',
|
||||
'datelist_min_max_time[hour]' => '8',
|
||||
];
|
||||
$this->drupalPostForm('webform/test_element_datelist', $edit, t('Submit'));
|
||||
$this->assertRaw('<em class="placeholder">datelist_min_max_time</em> must be on or after <em class="placeholder">2009-01-01 09:00:00</em>.');
|
||||
|
||||
// Check custom required error.
|
||||
$edit = [
|
||||
'datelist_required_error[year]' => '',
|
||||
|
|
|
@ -36,28 +36,50 @@ class WebformElementDateTimeTest extends WebformElementTestBase {
|
|||
$this->assertRaw('<input data-drupal-selector="edit-datetime-datepicker-timepicker-date" title="Date (e.g. ' . $now_date . ')" type="text" min="Mon, 01/01/1900" max="Sat, 12/31/2050" data-drupal-date-format="D, m/d/Y" id="edit-datetime-datepicker-timepicker-date" name="datetime_datepicker_timepicker[date]" value="Tue, 08/18/2009" size="15" maxlength="128" class="form-text" />');
|
||||
$this->assertRaw('<input data-drupal-selector="edit-datetime-datepicker-timepicker-time"');
|
||||
// Skip time which can change during the tests.
|
||||
$this->assertRaw('type="text" step="1" data-webform-time-format="g:i A" id="edit-datetime-datepicker-timepicker-time" name="datetime_datepicker_timepicker[time]" value="4:00 PM" size="12" maxlength="128" class="form-text" />');
|
||||
$this->assertRaw('type="text" step="1" data-webform-time-format="g:i A" id="edit-datetime-datepicker-timepicker-time" name="datetime_datepicker_timepicker[time]" value="4:00 PM" size="12" maxlength="10" class="form-time webform-time" />');
|
||||
|
||||
// Check time with custom min/max/step attributes.
|
||||
$this->assertRaw('<input min="2009-01-01" data-min-year="2009" max="2009-12-31" data-max-year="2009" data-drupal-selector="edit-datetime-time-min-max-date"');
|
||||
$this->assertRaw('<input min="09:00:00" data-min-year="2009" max="17:00:00" data-max-year="2009" data-drupal-selector="edit-datetime-time-min-max-time"');
|
||||
$this->assertRaw('<input min="09:00:00" max="17:00:00" data-drupal-selector="edit-datetime-time-min-max-time"');
|
||||
$this->assertRaw('<input min="Thu, 01/01/2009" data-min-year="2009" max="Thu, 12/31/2009" data-max-year="2009" data-drupal-selector="edit-datetime-datepicker-timepicker-time-min-max-date"');
|
||||
$this->assertRaw('<input min="09:00:00" data-min-year="2009" max="17:00:00" data-max-year="2009" data-drupal-selector="edit-datetime-datepicker-timepicker-time-min-max-time"');
|
||||
$this->assertRaw('<input min="09:00:00" max="17:00:00" data-drupal-selector="edit-datetime-datepicker-timepicker-time-min-max-time"');
|
||||
|
||||
// Check 'datelist' and 'datetime' #default_value.
|
||||
$form = $webform->getSubmissionForm();
|
||||
$this->assert($form['elements']['datetime_default']['#default_value'] instanceof DrupalDateTime, 'datetime_default #default_value instance of \Drupal\Core\Datetime\DrupalDateTime.');
|
||||
|
||||
// Check datetime #max validation.
|
||||
// Check datetime #date_date_max validation.
|
||||
$edit = ['datetime_min_max[date]' => '2010-08-18'];
|
||||
$this->drupalPostForm('webform/test_element_datetime', $edit, t('Submit'));
|
||||
$this->assertRaw('<em class="placeholder">datetime_min_max</em> must be on or before <em class="placeholder">2009-12-31</em>.');
|
||||
|
||||
// Check datetime #min validation.
|
||||
// Check datetime #date_date_min validation.
|
||||
$edit = ['datetime_min_max[date]' => '2006-08-18'];
|
||||
$this->drupalPostForm('webform/test_element_datetime', $edit, t('Submit'));
|
||||
$this->assertRaw('<em class="placeholder">datetime_min_max</em> must be on or after <em class="placeholder">2009-01-01</em>.');
|
||||
|
||||
// Check datetime #date_max date validation.
|
||||
$edit = ['datetime_min_max_time[date]' => '2009-12-31', 'datetime_min_max_time[time]' => '19:00:00'];
|
||||
$this->drupalPostForm('webform/test_element_datetime', $edit, t('Submit'));
|
||||
$this->assertRaw('<em class="placeholder">datetime_min_max_time</em> must be on or before <em class="placeholder">2009-12-31 17:00:00</em>.');
|
||||
|
||||
// Check datetime #date_min date validation.
|
||||
$edit = ['datetime_min_max_time[date]' => '2009-01-01', 'datetime_min_max_time[time]' => '08:00:00'];
|
||||
$this->drupalPostForm('webform/test_element_datetime', $edit, t('Submit'));
|
||||
$this->assertRaw('<em class="placeholder">datetime_min_max_time</em> must be on or after <em class="placeholder">2009-01-01 09:00:00</em>.');
|
||||
|
||||
// Check datetime #date_max time validation.
|
||||
$edit = ['datetime_min_max_time[time]' => '24:00:00'];
|
||||
$this->drupalPostForm('webform/test_element_datetime', $edit, t('Submit'));
|
||||
$this->assertRaw('<em class="placeholder">Time</em> must be on or before <em class="placeholder">17:00:00</em>.');
|
||||
$this->assertRaw('<em class="placeholder">datetime_min_max_time</em> must be on or after <em class="placeholder">2009-01-01 09:00:00</em>.');
|
||||
|
||||
// Check datetime #date_min time validation.
|
||||
$edit = ['datetime_min_max_time[time]' => '01:00:00'];
|
||||
$this->drupalPostForm('webform/test_element_datetime', $edit, t('Submit'));
|
||||
$this->assertRaw('<em class="placeholder">Time</em> must be on or after <em class="placeholder">09:00:00</em>.');
|
||||
$this->assertRaw('<em class="placeholder">datetime_min_max_time</em> must be on or after <em class="placeholder">2009-01-01 09:00:00</em>.');
|
||||
|
||||
// Check: Issue #2723159: Datetime form element cannot validate when using a
|
||||
// format without seconds.
|
||||
$sid = $this->postSubmission($webform);
|
||||
|
|
|
@ -90,7 +90,7 @@ class WebformElementFormatCustomTest extends WebformElementTestBase {
|
|||
$this->assertRaw('element.country: {country}<br/>');
|
||||
|
||||
// Check fieldset displayed as details.
|
||||
$this->assertRaw('<details data-webform-element-id="test_element_format_custom--fieldset_custom" class="webform-container webform-container-type-details js-form-wrapper form-wrapper" id="test_element_format_custom--fieldset_custom" open="open">');
|
||||
$this->assertRaw('<details class="webform-container webform-container-type-details js-form-wrapper form-wrapper" data-webform-element-id="test_element_format_custom--fieldset_custom" id="test_element_format_custom--fieldset_custom" open="open">');
|
||||
$this->assertRaw('<summary role="button" aria-controls="test_element_format_custom--fieldset_custom" aria-expanded="true" aria-pressed="true">fieldset_custom</summary>');
|
||||
|
||||
// Check container custom HTML format.
|
||||
|
|
|
@ -79,11 +79,11 @@ class WebformElementFormatTest extends WebformElementTestBase {
|
|||
// 'Entity autocomplete (Label (ID))' => 'admin (1)',
|
||||
];
|
||||
foreach ($elements as $label => $value) {
|
||||
$this->assertContains($body, '<b>' . $label . '</b><br />' . $value, new FormattableMarkup('Found @label: @value', ['@label' => $label, '@value' => $value]));
|
||||
$this->assertContains('<b>' . $label . '</b><br />' . $value, $body, new FormattableMarkup('Found @label: @value', ['@label' => $label, '@value' => $value]));
|
||||
}
|
||||
|
||||
// Check code format.
|
||||
$this->assertContains($body, '<pre class="js-webform-codemirror-runmode webform-codemirror-runmode" data-webform-codemirror-mode="text/x-yaml">message: \'Hello World\'</pre>');
|
||||
$this->assertContains('<pre class="js-webform-codemirror-runmode webform-codemirror-runmode" data-webform-codemirror-mode="text/x-yaml">message: \'Hello World\'</pre>', $body);
|
||||
|
||||
// Check elements formatted as text.
|
||||
$body = $this->getMessageBody($submission, 'email_text');
|
||||
|
@ -110,7 +110,7 @@ class WebformElementFormatTest extends WebformElementTestBase {
|
|||
'Time (Raw value): 09:00:00',
|
||||
];
|
||||
foreach ($elements as $value) {
|
||||
$this->assertContains($body, $value, new FormattableMarkup('Found @value', ['@value' => $value]));
|
||||
$this->assertContains($value, $body, new FormattableMarkup('Found @value', ['@value' => $value]));
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
|
@ -136,7 +136,7 @@ class WebformElementFormatTest extends WebformElementTestBase {
|
|||
'File (URL)' => $this->getSubmissionFileUrl($submission, 'managed_file_url'),
|
||||
];
|
||||
foreach ($elements as $label => $value) {
|
||||
$this->assertContains($body, '<b>' . $label . '</b><br />' . $value, new FormattableMarkup('Found @label: @value', ['@label' => $label, '@value' => $value]));
|
||||
$this->assertContains('<b>' . $label . '</b><br />' . $value, $body, new FormattableMarkup('Found @label: @value', ['@label' => $label, '@value' => $value]));
|
||||
}
|
||||
|
||||
// Check managed file element formatted as text.
|
||||
|
@ -151,7 +151,7 @@ class WebformElementFormatTest extends WebformElementTestBase {
|
|||
'File (URL): ' . $this->getSubmissionFileUrl($submission, 'managed_file_url'),
|
||||
];
|
||||
foreach ($elements as $value) {
|
||||
$this->assertContains($body, $value, new FormattableMarkup('Found @value', ['@value' => $value]));
|
||||
$this->assertContains($value, $body, new FormattableMarkup('Found @value', ['@value' => $value]));
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
|
@ -178,7 +178,10 @@ class WebformElementFormatTest extends WebformElementTestBase {
|
|||
'Checkboxes (Unordered list)' => '<div class="item-list"><ul><li>One</li><li>Two</li><li>Three</li></ul>',
|
||||
];
|
||||
foreach ($elements as $label => $value) {
|
||||
$this->assertContains($body, '<b>' . $label . '</b><br />' . $value, new FormattableMarkup('Found @label: @value', ['@label' => $label, '@value' => $value]));
|
||||
$this->assertContains('<b>' . $label . '</b><br />' . $value, $body, new FormattableMarkup('Found @label: @value', [
|
||||
'@label' => $label,
|
||||
'@value' => $value
|
||||
]));
|
||||
}
|
||||
|
||||
// Check elements formatted as text.
|
||||
|
@ -208,7 +211,7 @@ class WebformElementFormatTest extends WebformElementTestBase {
|
|||
- Three',
|
||||
];
|
||||
foreach ($elements as $value) {
|
||||
$this->assertContains($body, $value, new FormattableMarkup('Found @value', ['@value' => $value]));
|
||||
$this->assertContains($value, $body, new FormattableMarkup('Found @value', ['@value' => $value]));
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
|
@ -232,7 +235,10 @@ class WebformElementFormatTest extends WebformElementTestBase {
|
|||
'raw:' => '1, 2, 3',
|
||||
];
|
||||
foreach ($elements as $label => $value) {
|
||||
$this->assertContains($body, '<h3>' . $label . '</h3>' . $value . '<hr />', new FormattableMarkup('Found @label: @value', ['@label' => $label, '@value' => $value]));
|
||||
$this->assertContains('<h3>' . $label . '</h3>' . $value . '<hr />', $body, new FormattableMarkup('Found @label: @value', [
|
||||
'@label' => $label,
|
||||
'@value' => $value
|
||||
]));
|
||||
}
|
||||
|
||||
// Check elements tokens formatted as text.
|
||||
|
@ -247,7 +253,7 @@ class WebformElementFormatTest extends WebformElementTestBase {
|
|||
"raw:\n1, 2, 3",
|
||||
];
|
||||
foreach ($elements as $value) {
|
||||
$this->assertContains($body, $value, new FormattableMarkup('Found @value', ['@value' => $value]));
|
||||
$this->assertContains($value, $body, new FormattableMarkup('Found @value', ['@value' => $value]));
|
||||
}
|
||||
|
||||
// Check element default format item global setting.
|
||||
|
@ -255,14 +261,14 @@ class WebformElementFormatTest extends WebformElementTestBase {
|
|||
->set('format.checkboxes.item', 'raw')
|
||||
->save();
|
||||
$body = $this->getMessageBody($webform_format_token_submission, 'email_text');
|
||||
$this->assertContains($body, "default:\n1, 2, 3");
|
||||
$this->assertContains("default:\n1, 2, 3", $body);
|
||||
|
||||
// Check element default format items global setting.
|
||||
\Drupal::configFactory()->getEditable('webform.settings')
|
||||
->set('format.checkboxes.items', 'and')
|
||||
->save();
|
||||
$body = $this->getMessageBody($webform_format_token_submission, 'email_text');
|
||||
$this->assertContains($body, "default:\n1, 2, and 3");
|
||||
$this->assertContains("default:\n1, 2, and 3", $body);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -0,0 +1,96 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\webform\Tests\Element;
|
||||
|
||||
use Drupal\webform\Entity\Webform;
|
||||
|
||||
/**
|
||||
* Tests for element input mask.
|
||||
*
|
||||
* @group Webform
|
||||
*/
|
||||
class WebformElementInputMaskTest extends WebformElementTestBase {
|
||||
|
||||
/**
|
||||
* Webforms to load.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected static $testWebforms = ['test_element_input_mask'];
|
||||
|
||||
/**
|
||||
* Test element input mask.
|
||||
*/
|
||||
public function testInputMask() {
|
||||
$webform = Webform::load('test_element_input_mask');
|
||||
|
||||
// Check default values.
|
||||
$this->postSubmission($webform);
|
||||
$this->assertRaw("currency: ''
|
||||
datetime: ''
|
||||
decimal: ''
|
||||
email: ''
|
||||
ip: ''
|
||||
license_plate: ''
|
||||
mac: ''
|
||||
percentage: ''
|
||||
phone: ''
|
||||
ssn: ''
|
||||
vin: ''
|
||||
zip: ''
|
||||
uppercase: ''
|
||||
lowercase: ''
|
||||
custom: ''");
|
||||
|
||||
// Check patterns.
|
||||
$edit = [
|
||||
'email' => 'example@example.com',
|
||||
'datetime' => '2007-06-09\'T\'17:46:21',
|
||||
'decimal' => '9.9',
|
||||
'ip' => '255.255.255.255',
|
||||
'currency' => '$ 9.99',
|
||||
'percentage' => '99 %',
|
||||
'phone' => '(999) 999-9999',
|
||||
'license_plate' => '9-AAA-999',
|
||||
'mac' => '99-99-99-99-99-99',
|
||||
'ssn' => '999-99-9999',
|
||||
'vin' => 'JA3AY11A82U020534',
|
||||
'zip' => '99999-9999',
|
||||
'uppercase' => 'UPPERCASE',
|
||||
'lowercase' => 'lowercase',
|
||||
];
|
||||
$this->postSubmission($webform, $edit);
|
||||
$this->assertRaw("currency: '$ 9.99'
|
||||
datetime: '2007-06-09''T''17:46:21'
|
||||
decimal: '9.9'
|
||||
email: example@example.com
|
||||
ip: 255.255.255.255
|
||||
license_plate: 9-AAA-999
|
||||
mac: 99-99-99-99-99-99
|
||||
percentage: '99 %'
|
||||
phone: '(999) 999-9999'
|
||||
ssn: 999-99-9999
|
||||
vin: JA3AY11A82U020534
|
||||
zip: 99999-9999
|
||||
uppercase: UPPERCASE
|
||||
lowercase: lowercase
|
||||
custom: ''");
|
||||
|
||||
// Check pattern validation error messages.
|
||||
$edit = [
|
||||
'currency' => '$ 9.9_',
|
||||
'decimal' => '9._',
|
||||
'ip' => '255.255.255.__',
|
||||
'mac' => '99-99-99-99-99-_)',
|
||||
'percentage' => '_ %',
|
||||
'phone' => '(999) 999-999_',
|
||||
'ssn' => '999-99-999_',
|
||||
'zip' => '99999-999_',
|
||||
];
|
||||
$this->postSubmission($webform, $edit);
|
||||
foreach ($edit as $name => $value) {
|
||||
$this->assertRaw('<em class="placeholder">' . $name . '</em> field is not in the right format.');
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,58 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\webform\Tests\Element;
|
||||
|
||||
/**
|
||||
* Test for webform element managed file preview.
|
||||
*
|
||||
* @group Webform
|
||||
*/
|
||||
class WebformElementManagedFilePreviewTest extends WebformElementManagedFileTestBase {
|
||||
|
||||
/**
|
||||
* Modules to enable.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $modules = ['file', 'image', 'webform'];
|
||||
|
||||
/**
|
||||
* Webforms to load.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected static $testWebforms = ['test_element_managed_file_prev'];
|
||||
|
||||
/**
|
||||
* Test image file upload.
|
||||
*/
|
||||
public function testImageFileUpload() {
|
||||
global $base_url;
|
||||
|
||||
// Check that anonymous users can not preview files.
|
||||
$this->drupalGet('webform/test_element_managed_file_prev/test');
|
||||
$this->assertRaw('<span data-drupal-selector="edit-webform-image-file-file-1-filename" class="file file--mime-image-gif file--image"> webform_image_file.gif</span>');
|
||||
$this->assertRaw('<span data-drupal-selector="edit-webform-audio-file-file-3-filename" class="file file--mime-audio-mpeg file--audio"> webform_audio_file.mp3</span>');
|
||||
$this->assertRaw('<span data-drupal-selector="edit-webform-video-file-file-5-filename" class="file file--mime-video-mp4 file--video"> webform_video_file.mp4</span>');
|
||||
$this->assertRaw('<span data-drupal-selector="edit-webform-document-file-file-7-filename" class="file file--mime-text-plain file--text"> webform_document_file.txt</span>');
|
||||
|
||||
// Login admin user.
|
||||
$this->drupalLogin($this->rootUser);
|
||||
|
||||
// Check that authenticated users can preview files.
|
||||
$this->drupalGet('webform/test_element_managed_file_prev/test');
|
||||
|
||||
$this->assertRaw('<div class="webform-managed-file-preview webform-image-file-preview js-form-wrapper form-wrapper" data-drupal-selector="edit-webform-image-file-file-9-filename" id="edit-webform-image-file-file-9-filename">');
|
||||
$this->assertRaw('<a href="' . $base_url . '/system/files/webform/test_element_managed_file_prev/_sid_/webform_image_file_0.gif" class="js-webform-image-file-modal webform-image-file-modal">');
|
||||
|
||||
$this->assertRaw('<div class="webform-managed-file-preview webform-audio-file-preview js-form-wrapper form-wrapper" data-drupal-selector="edit-webform-audio-file-file-11-filename" id="edit-webform-audio-file-file-11-filename">');
|
||||
$this->assertRaw('<source src="' . $base_url . '/system/files/webform/test_element_managed_file_prev/_sid_/webform_audio_file_0.mp3" type="audio/mpeg">');
|
||||
|
||||
$this->assertRaw('<div class="webform-managed-file-preview webform-video-file-preview js-form-wrapper form-wrapper" data-drupal-selector="edit-webform-video-file-file-13-filename" id="edit-webform-video-file-file-13-filename">');
|
||||
$this->assertRaw('<source src="' . $base_url . '/system/files/webform/test_element_managed_file_prev/_sid_/webform_video_file_0.mp4" type="video/mp4">');
|
||||
|
||||
$this->assertRaw('<div class="webform-managed-file-preview webform-document-file-preview js-form-wrapper form-wrapper" data-drupal-selector="edit-webform-document-file-file-15-filename" id="edit-webform-document-file-file-15-filename">');
|
||||
$this->assertRaw($base_url . '/system/files/webform/test_element_managed_file_prev/_sid_/webform_document_file_0.txt');
|
||||
}
|
||||
|
||||
}
|
|
@ -78,6 +78,20 @@ class WebformElementManagedFileTest extends WebformElementManagedFileTestBase {
|
|||
|
||||
$this->checkFileUpload('single', $this->files[0], $this->files[1]);
|
||||
$this->checkFileUpload('multiple', $this->files[2], $this->files[3]);
|
||||
|
||||
/* File placeholder */
|
||||
|
||||
// Check placeholder is displayed.
|
||||
$this->drupalGet('webform/test_element_managed_file');
|
||||
$this->assertRaw('<div class="webform-managed-file-placeholder managed-file-placeholder js-form-wrapper form-wrapper" data-drupal-selector="edit-managed-file-single-placeholder-file-placeholder" id="edit-managed-file-single-placeholder-file-placeholder">This is the single file upload placeholder</div>');
|
||||
$this->assertRaw('<div class="webform-managed-file-placeholder managed-file-placeholder js-form-wrapper form-wrapper" data-drupal-selector="edit-managed-file-multiple-placeholder-file-placeholder" id="edit-managed-file-multiple-placeholder-file-placeholder">This is the multiple file upload placeholder</div>');
|
||||
|
||||
$this->drupalLogin($this->rootUser);
|
||||
|
||||
// Check placeholder is not displayed when files are uploaded.
|
||||
$this->drupalGet('webform/test_element_managed_file/test');
|
||||
$this->assertNoRaw('<div class="webform-managed-file-placeholder managed-file-placeholder js-form-wrapper form-wrapper" data-drupal-selector="edit-managed-file-single-placeholder-file-placeholder" id="edit-managed-file-single-placeholder-file-placeholder">This is the single file upload placeholder</div>');
|
||||
$this->assertNoRaw('<div class="webform-managed-file-placeholder managed-file-placeholder js-form-wrapper form-wrapper" data-drupal-selector="edit-managed-file-multiple-placeholder-file-placeholder" id="edit-managed-file-multiple-placeholder-file-placeholder">This is the multiple file upload placeholder</div>');
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -85,7 +99,7 @@ class WebformElementManagedFileTest extends WebformElementManagedFileTestBase {
|
|||
*
|
||||
* The property #file_name_pattern is tested.
|
||||
*/
|
||||
protected function testFileRename() {
|
||||
public function testFileRename() {
|
||||
$webform = Webform::load('test_element_managed_file_name');
|
||||
|
||||
$source_for_filename = $this->randomMachineName();
|
||||
|
@ -124,7 +138,7 @@ class WebformElementManagedFileTest extends WebformElementManagedFileTestBase {
|
|||
/**
|
||||
* Test file management.
|
||||
*/
|
||||
protected function testFileManagement() {
|
||||
public function testFileManagement() {
|
||||
$this->drupalLogin($this->rootUser);
|
||||
|
||||
$webform = Webform::load('test_element_managed_file');
|
||||
|
@ -191,7 +205,7 @@ class WebformElementManagedFileTest extends WebformElementManagedFileTestBase {
|
|||
/**
|
||||
* Test file upload with disabled results.
|
||||
*/
|
||||
protected function testFileUploadWithDisabledResults() {
|
||||
public function testFileUploadWithDisabledResults() {
|
||||
$this->drupalLogin($this->rootUser);
|
||||
|
||||
$webform = Webform::load('test_element_managed_file_dis');
|
||||
|
|
|
@ -101,8 +101,22 @@ states_custom_condition:
|
|||
$this->assertRaw('<textarea data-drupal-selector="edit-states-unsupported-nesting-states" aria-describedby="edit-states-unsupported-nesting-states--description" class="js-webform-codemirror webform-codemirror yaml form-textarea resize-vertical" data-webform-codemirror-mode="text/x-yaml" id="edit-states-unsupported-nesting-states" name="states_unsupported_nesting[states]" rows="5" cols="60">');
|
||||
|
||||
// Check 'States single' (#multiple: FALSE)
|
||||
$this->assertFieldById('edit-states-empty-add');
|
||||
$this->assertNoFieldById('edit-states-single-add');
|
||||
$this->assertFieldById('edit-states-empty-actions-add');
|
||||
$this->assertNoFieldById('edit-states-single-actions-add');
|
||||
|
||||
/**************************************************************************/
|
||||
// Validation.
|
||||
/**************************************************************************/
|
||||
|
||||
// Check duplicate states validation.
|
||||
$edit = ['states_basic[states][0][state]' => 'required'];
|
||||
$this->drupalPostForm('webform/test_element_states', $edit, t('Submit'));
|
||||
$this->assertRaw('The <em class="placeholder">Required</em> state is declared more than once. There can only be one declaration per state.');
|
||||
|
||||
// Check duplicate selectors validation.
|
||||
$edit = ['states_basic[states][3][selector]' => 'selector_02'];
|
||||
$this->drupalPostForm('webform/test_element_states', $edit, t('Submit'));
|
||||
$this->assertRaw('The <em class="placeholder">Selector 02 (selector_02)</em> element is used more than once within the <em class="placeholder">Required</em> state. To use multiple values within a trigger try using the pattern trigger.');
|
||||
|
||||
/**************************************************************************/
|
||||
// Processing.
|
||||
|
@ -156,6 +170,25 @@ states_custom_condition:
|
|||
$this->assertNoFieldByName('states_empty[states][2][selector]', 'selector_02');
|
||||
$this->assertNoFieldByName('states_empty[states][2][trigger]', 'value');
|
||||
$this->assertNoFieldByName('states_empty[states][2][value]', '{value_02}');
|
||||
|
||||
/**************************************************************************/
|
||||
// Edit source.
|
||||
/**************************************************************************/
|
||||
|
||||
// Check that 'Edit source' button is not available.
|
||||
$this->drupalGet('webform/test_element_states');
|
||||
$this->assertNoRaw('<input class="button button--danger js-form-submit form-submit" data-drupal-selector="edit-states-basic-actions-source" formnovalidate="formnovalidate" type="submit" id="edit-states-basic-actions-source" name="states_basic_table_source" value="Edit source" />');
|
||||
|
||||
// Check that 'Edit source' button is available.
|
||||
$this->drupalLogin($this->rootUser);
|
||||
$this->drupalGet('webform/test_element_states');
|
||||
$this->assertRaw('<input class="button button--danger js-form-submit form-submit" data-drupal-selector="edit-states-basic-actions-source" formnovalidate="formnovalidate" type="submit" id="edit-states-basic-actions-source" name="states_basic_table_source" value="Edit source" />');
|
||||
$this->assertNoFieldByName('states_basic[states]');
|
||||
|
||||
// Check that 'source' is editable.
|
||||
$this->drupalPostAjaxForm(NULL, [], 'states_basic_table_source');
|
||||
$this->assertRaw('Creating custom conditional logic (Form API #states) with nested conditions or custom selectors will disable the conditional logic builder. This will require that Form API #states be manually entered.');
|
||||
$this->assertFieldByName('states_basic[states]');
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -24,11 +24,11 @@ class WebformElementTimeTest extends WebformElementTestBase {
|
|||
|
||||
// Check time element.
|
||||
$this->assertRaw('<label for="edit-time-12-hour">time_12_hour</label>');
|
||||
$this->assertRaw('<input data-drupal-selector="edit-time-12-hour" data-webform-time-format="g:i A" type="time" id="edit-time-12-hour" name="time_12_hour" value="14:00" size="10" class="form-time webform-time" />');
|
||||
$this->assertRaw('<input data-drupal-selector="edit-time-12-hour" data-webform-time-format="g:i A" type="time" id="edit-time-12-hour" name="time_12_hour" value="14:00" size="10" maxlength="10" class="form-time webform-time" />');
|
||||
|
||||
// Check timepicker elements.
|
||||
$this->assertRaw('<input data-drupal-selector="edit-time-timepicker" data-webform-time-format="g:i A" type="text" id="edit-time-timepicker" name="time_timepicker" value="2:00 PM" size="10" class="form-time webform-time" />');
|
||||
$this->assertRaw('<input data-drupal-selector="edit-time-timepicker-min-max" aria-describedby="edit-time-timepicker-min-max--description" data-webform-time-format="g:i A" type="text" id="edit-time-timepicker-min-max" name="time_timepicker_min_max" value="2:00 PM" size="10" min="14:00" max="18:00" class="form-time webform-time" />');
|
||||
$this->assertRaw('<input data-drupal-selector="edit-time-timepicker" data-webform-time-format="g:i A" type="text" id="edit-time-timepicker" name="time_timepicker" value="2:00 PM" size="10" maxlength="10" class="form-time webform-time" />');
|
||||
$this->assertRaw('<input data-drupal-selector="edit-time-timepicker-min-max" aria-describedby="edit-time-timepicker-min-max--description" data-webform-time-format="g:i A" type="text" id="edit-time-timepicker-min-max" name="time_timepicker_min_max" value="2:00 PM" size="10" maxlength="10" min="14:00" max="18:00" class="form-time webform-time" />');
|
||||
|
||||
// Check time validation.
|
||||
$edit = ['time_24_hour' => 'not-valid'];
|
||||
|
|
|
@ -32,6 +32,7 @@ class WebformElementValidateUniqueTest extends WebformElementTestBase {
|
|||
'unique_user_textfield' => '{unique_user_textfield}',
|
||||
'unique_entity_textfield' => '{unique_entity_textfield}',
|
||||
'unique_error' => '{unique_error}',
|
||||
'unique_multiple[1]' => TRUE,
|
||||
];
|
||||
|
||||
// Check post submission with default values does not trigger
|
||||
|
@ -42,7 +43,7 @@ class WebformElementValidateUniqueTest extends WebformElementTestBase {
|
|||
$this->assertNoRaw('unique_user_textfield error message.');
|
||||
$this->assertNoRaw('unique_entity_textfield error message.');
|
||||
$this->assertNoRaw('unique_error error message.');
|
||||
$this->assertNoRaw('unique_ignored error message.');
|
||||
$this->assertNoRaw('unique_multiple error message.');
|
||||
|
||||
// Check post duplicate submission with default values does trigger
|
||||
// unique errors.
|
||||
|
@ -52,7 +53,7 @@ class WebformElementValidateUniqueTest extends WebformElementTestBase {
|
|||
$this->assertRaw('unique_user_textfield error message.');
|
||||
$this->assertRaw('unique_entity_textfield error message.');
|
||||
$this->assertRaw('unique_error error message.');
|
||||
$this->assertNoRaw('unique_ignored error message.');
|
||||
$this->assertRaw('unique_multiple error message.');
|
||||
|
||||
// Check #unique element can be updated.
|
||||
$this->drupalPostForm("admin/structure/webform/manage/test_element_validate_unique/submission/$sid/edit", [], t('Save'));
|
||||
|
@ -60,7 +61,7 @@ class WebformElementValidateUniqueTest extends WebformElementTestBase {
|
|||
$this->assertNoRaw('unique_user_textfield error message.');
|
||||
$this->assertNoRaw('unique_entity_textfield error message.');
|
||||
$this->assertNoRaw('unique_error error message.');
|
||||
$this->assertNoRaw('unique_ignored error message.');
|
||||
$this->assertNoRaw('unique_multiple error message.');
|
||||
|
||||
// Check #unique multiple validation within the same element.
|
||||
// @see \Drupal\webform\Plugin\WebformElementBase::validateUniqueMultiple
|
||||
|
|
|
@ -130,14 +130,14 @@ class WebformHandlerEmailAdvancedTest extends WebformTestBase {
|
|||
$this->assertEqual($sent_email['subject'], 'This has "special" \'chararacters\'');
|
||||
|
||||
// Check email body is HTML.
|
||||
$this->assertContains($sent_email['params']['body'], '<b>First name</b><br />John<br /><br />');
|
||||
$this->assertContains($sent_email['params']['body'], '<b>Last name</b><br />Smith<br /><br />');
|
||||
$this->assertContains($sent_email['params']['body'], '<b>Email</b><br /><a href="mailto:from@example.com">from@example.com</a><br /><br />');
|
||||
$this->assertContains($sent_email['params']['body'], '<b>Subject</b><br />This has <removed>"special" 'chararacters'<br /><br />');
|
||||
$this->assertContains($sent_email['params']['body'], '<b>Message</b><br /><p><em>Please enter a message.</em> Test that double "quotes" are not encoded.</p><br /><br />');
|
||||
$this->assertContains($sent_email['params']['body'], '<p style="color:yellow"><em>Custom styled HTML markup</em></p>');
|
||||
$this->assertNotContains($sent_email['params']['body'], '<b>Optional</b><br />{Empty}<br /><br />');
|
||||
$this->assertNotContains($sent_email['params']['body'], '<b>Checkbox/b><br />Yes<br /><br />');
|
||||
$this->assertContains('<b>First name</b><br />John<br /><br />', $sent_email['params']['body']);
|
||||
$this->assertContains('<b>Last name</b><br />Smith<br /><br />', $sent_email['params']['body']);
|
||||
$this->assertContains('<b>Email</b><br /><a href="mailto:from@example.com">from@example.com</a><br /><br />', $sent_email['params']['body']);
|
||||
$this->assertContains('<b>Subject</b><br />This has <removed>"special" 'chararacters'<br /><br />', $sent_email['params']['body']);
|
||||
$this->assertContains('<b>Message</b><br /><p><em>Please enter a message.</em> Test that double "quotes" are not encoded.</p><br /><br />', $sent_email['params']['body']);
|
||||
$this->assertContains('<p style="color:yellow"><em>Custom styled HTML markup</em></p>', $sent_email['params']['body']);
|
||||
$this->assertNotContains('<b>Optional</b><br />{Empty}<br /><br />', $sent_email['params']['body']);
|
||||
$this->assertNotContains('<b>Checkbox/b><br />Yes<br /><br />', $sent_email['params']['body']);
|
||||
|
||||
// Check email has attachment.
|
||||
$this->assertEqual($sent_email['params']['attachments'][0]['filecontent'], "this is a sample txt file\nit has two lines\n");
|
||||
|
@ -152,7 +152,7 @@ class WebformHandlerEmailAdvancedTest extends WebformTestBase {
|
|||
// Check resend webform with custom message.
|
||||
$this->drupalPostForm("admin/structure/webform/manage/test_handler_email_advanced/submission/$sid/resend", ['message[body][value]' => 'Testing 123…'], t('Resend message'));
|
||||
$sent_email = $this->getLastEmail();
|
||||
$this->assertNotContains($sent_email['params']['body'], '<b>First name</b><br />John<br /><br />');
|
||||
$this->assertNotContains('<b>First name</b><br />John<br /><br />', $sent_email['params']['body']);
|
||||
$this->debug($sent_email['params']['body']);
|
||||
$this->assertEqual($sent_email['params']['body'], 'Testing 123…');
|
||||
|
||||
|
@ -177,7 +177,7 @@ class WebformHandlerEmailAdvancedTest extends WebformTestBase {
|
|||
// Check empty element is excluded.
|
||||
$this->postSubmission($webform);
|
||||
$sent_email = $this->getLastEmail();
|
||||
$this->assertNotContains($sent_email['params']['body'], '<b>Optional</b><br />{Empty}<br /><br />');
|
||||
$this->assertNotContains('<b>Optional</b><br />{Empty}<br /><br />', $sent_email['params']['body']);
|
||||
|
||||
// Include empty.
|
||||
$configuration = $email_handler->getConfiguration();
|
||||
|
@ -189,8 +189,8 @@ class WebformHandlerEmailAdvancedTest extends WebformTestBase {
|
|||
// Check empty included.
|
||||
$this->postSubmission($webform);
|
||||
$sent_email = $this->getLastEmail();
|
||||
$this->assertContains($sent_email['params']['body'], '<b>Optional</b><br />{Empty}<br /><br />');
|
||||
$this->assertContains($sent_email['params']['body'], '<b>Checkbox</b><br />No<br /><br />');
|
||||
$this->assertContains('<b>Optional</b><br />{Empty}<br /><br />', $sent_email['params']['body']);
|
||||
$this->assertContains('<b>Checkbox</b><br />No<br /><br />', $sent_email['params']['body']);
|
||||
|
||||
// Logut and use anonymous user account.
|
||||
$this->drupalLogout();
|
||||
|
@ -198,7 +198,7 @@ class WebformHandlerEmailAdvancedTest extends WebformTestBase {
|
|||
// Check that private is include in email because 'ignore_access' is TRUE.
|
||||
$this->postSubmission($webform);
|
||||
$sent_email = $this->getLastEmail();
|
||||
$this->assertContains($sent_email['params']['body'], '<b>Notes</b><br />These notes are private.<br /><br />');
|
||||
$this->assertContains('<b>Notes</b><br />These notes are private.<br /><br />', $sent_email['params']['body']);
|
||||
|
||||
// Disable ignore_access.
|
||||
$email_handler = $webform->getHandler('email');
|
||||
|
@ -210,7 +210,7 @@ class WebformHandlerEmailAdvancedTest extends WebformTestBase {
|
|||
// Check that private is excluded from email because 'ignore_access' is FALSE.
|
||||
$this->postSubmission($webform);
|
||||
$sent_email = $this->getLastEmail();
|
||||
$this->assertNotContains($sent_email['params']['body'], '<b>Notes</b><br />These notes are private.<br /><br />');
|
||||
$this->assertNotContains('<b>Notes</b><br />These notes are private.<br /><br />', $sent_email['params']['body']);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -41,9 +41,9 @@ class WebformHandlerEmailBasicTest extends WebformTestBase {
|
|||
$sent_email = $this->getLastEmail();
|
||||
$this->assertEqual($sent_email['key'], 'test_handler_email_email');
|
||||
$this->assertEqual($sent_email['reply-to'], "John Smith <from@example.com>");
|
||||
$this->assertContains($sent_email['body'], 'Submitted by: Anonymous');
|
||||
$this->assertContains($sent_email['body'], 'First name: John');
|
||||
$this->assertContains($sent_email['body'], 'Last name: Smith');
|
||||
$this->assertContains('Submitted by: Anonymous', $sent_email['body']);
|
||||
$this->assertContains('First name: John', $sent_email['body']);
|
||||
$this->assertContains('Last name: Smith', $sent_email['body']);
|
||||
$this->assertEqual($sent_email['headers']['From'], 'John Smith <from@example.com>');
|
||||
$this->assertEqual($sent_email['headers']['Cc'], 'cc@example.com');
|
||||
$this->assertEqual($sent_email['headers']['Bcc'], 'bcc@example.com');
|
||||
|
@ -56,8 +56,8 @@ class WebformHandlerEmailBasicTest extends WebformTestBase {
|
|||
$webform->setSetting('results_disabled', TRUE)->save();
|
||||
$this->postSubmission($webform, ['first_name' => 'Jane', 'last_name' => 'Doe']);
|
||||
$sent_email = $this->getLastEmail();
|
||||
$this->assertContains($sent_email['body'], 'First name: Jane');
|
||||
$this->assertContains($sent_email['body'], 'Last name: Doe');
|
||||
$this->assertContains('First name: Jane', $sent_email['body']);
|
||||
$this->assertContains('Last name: Doe', $sent_email['body']);
|
||||
$webform->setSetting('results_disabled', FALSE)->save();
|
||||
|
||||
// Check sending a custom email using tokens.
|
||||
|
@ -81,17 +81,20 @@ class WebformHandlerEmailBasicTest extends WebformTestBase {
|
|||
$webform_submission = WebformSubmission::load($sid);
|
||||
|
||||
$sent_email = $this->getLastEmail();
|
||||
$this->assertContains($sent_email['body'], 'full name: John Smith');
|
||||
$this->assertContains($sent_email['body'], 'uuid: ' . $webform_submission->uuid->value);
|
||||
$this->assertContains($sent_email['body'], 'sid: ' . $sid);
|
||||
$this->assertContains($sent_email['body'], 'date: ' . \Drupal::service('date.formatter')->format($webform_submission->created->value, 'medium'));
|
||||
$this->assertContains($sent_email['body'], 'ip-address: ' . $webform_submission->remote_addr->value);
|
||||
$this->assertContains($sent_email['body'], 'user: ' . $admin_user->label());
|
||||
$this->assertContains($sent_email['body'], "url:");
|
||||
$this->assertContains($sent_email['body'], $webform_submission->toUrl('canonical', ['absolute' => TRUE])->toString());
|
||||
$this->assertContains($sent_email['body'], "edit-url:");
|
||||
$this->assertContains($sent_email['body'], $webform_submission->toUrl('edit-form', ['absolute' => TRUE])->toString());
|
||||
$this->assertContains($sent_email['body'], 'Test that "double quotes" are not encoded.');
|
||||
$this->assertContains('full name: John Smith', $sent_email['body']);
|
||||
$this->assertContains('uuid: ' . $webform_submission->uuid->value, $sent_email['body']);
|
||||
$this->assertContains('sid: ' . $sid, $sent_email['body']);
|
||||
$date_value = \Drupal::service('date.formatter')->format($webform_submission->created->value, 'medium');
|
||||
$this->assertContains('date: ' . $date_value, $sent_email['body']);
|
||||
$this->assertContains('ip-address: ' . $webform_submission->remote_addr->value, $sent_email['body']);
|
||||
$this->assertContains('user: ' . $admin_user->label(), $sent_email['body']);
|
||||
$this->assertContains("url:", $sent_email['body']);
|
||||
$this->assertContains($webform_submission->toUrl('canonical', ['absolute' => TRUE])
|
||||
->toString(), $sent_email['body']);
|
||||
$this->assertContains("edit-url:", $sent_email['body']);
|
||||
$this->assertContains($webform_submission->toUrl('edit-form', ['absolute' => TRUE])
|
||||
->toString(), $sent_email['body']);
|
||||
$this->assertContains('Test that "double quotes" are not encoded.', $sent_email['body']);
|
||||
|
||||
// Create a submission using HTML is subject and message.
|
||||
$edit = [
|
||||
|
@ -113,7 +116,7 @@ class WebformHandlerEmailBasicTest extends WebformTestBase {
|
|||
];
|
||||
$this->postSubmission($webform, $edit);
|
||||
$sent_email = $this->getLastEmail();
|
||||
$this->assertEqual($sent_email['reply-to'], '"first_name" "last_name" <from@example.com>');
|
||||
$this->assertEqual($sent_email['reply-to'], '"first_name\\" \\"last_name" <from@example.com>');
|
||||
$this->assertEqual($sent_email['subject'], 'This has & "special" \'characters\'');
|
||||
// NOTE:
|
||||
// Drupal's PhpMail::format function calls
|
||||
|
|
|
@ -224,7 +224,8 @@ options:
|
|||
custom_header: 'true'");
|
||||
|
||||
// Check request URL contains query string.
|
||||
$this->assertRaw("http://webform-test-handler-remote-post/completed?custom_completed=1&custom_data=1&first_name=John&last_name=Smith&response_type=200");
|
||||
// @todo restore tests once the Drupal 8.6.x issue is resolved.
|
||||
//$this->assertRaw("http://webform-test-handler-remote-post/completed?custom_completed=1&custom_data=1&first_name=John&last_name=Smith&response_type=200");
|
||||
|
||||
// Check response data.
|
||||
$this->assertRaw("message: 'Processed completed request.'");
|
||||
|
|
|
@ -176,6 +176,41 @@ class WebformHandlerTest extends WebformTestBase {
|
|||
$this->drupalPostForm('admin/structure/webform/manage/test_handler_test/handlers/add/test', ['handler_id' => 'test'], t('Save'));
|
||||
$this->assertRaw('The webform handler was successfully added.');
|
||||
$this->assertRaw('Invoked test: Drupal\webform_test_handler\Plugin\WebformHandler\TestWebformHandler:createHandler');
|
||||
|
||||
/**************************************************************************/
|
||||
// Single handler.
|
||||
/**************************************************************************/
|
||||
|
||||
// Check test handler is executed.
|
||||
$this->drupalGet('webform/test_handler_test/test');
|
||||
$this->assertRaw('Invoked test: Drupal\webform_test_handler\Plugin\WebformHandler\TestWebformHandler:preCreate');
|
||||
$this->assertRaw('Invoked test: Drupal\webform_test_handler\Plugin\WebformHandler\TestWebformHandler:postCreate');
|
||||
$this->assertRaw('Invoked test: Drupal\webform_test_handler\Plugin\WebformHandler\TestWebformHandler:alterElements');
|
||||
$this->assertRaw('Invoked test: Drupal\webform_test_handler\Plugin\WebformHandler\TestWebformHandler:overrideSettings');
|
||||
$this->assertRaw('Invoked test: Drupal\webform_test_handler\Plugin\WebformHandler\TestWebformHandler:alterForm');
|
||||
|
||||
// Check test handler is enabled and debug handler is disabled.
|
||||
$this->drupalPostForm('webform/test_handler_test/test', ['element' => ''], t('Submit'));
|
||||
$this->assertRaw('One two one two this is just a test');
|
||||
$this->assertNoRaw("element: ''");
|
||||
|
||||
// Check test handler is disabled.
|
||||
$this->drupalGet('webform/test_handler_test/test', ['query' => ['_webform_handler' => 'debug']]);
|
||||
$this->assertNoRaw('Invoked test: Drupal\webform_test_handler\Plugin\WebformHandler\TestWebformHandler:preCreate');
|
||||
$this->assertNoRaw('Invoked test: Drupal\webform_test_handler\Plugin\WebformHandler\TestWebformHandler:postCreate');
|
||||
$this->assertNoRaw('Invoked test: Drupal\webform_test_handler\Plugin\WebformHandler\TestWebformHandler:alterElements');
|
||||
$this->assertNoRaw('Invoked test: Drupal\webform_test_handler\Plugin\WebformHandler\TestWebformHandler:overrideSettings');
|
||||
$this->assertRaw('Testing the <em class="placeholder">Test: Handler: Test invoke methods</em> webform <em class="placeholder">Debug</em> handler. <strong>All other emails/handlers are disabled.</strong>');
|
||||
|
||||
// Check test handler is now disabled and debug handler is enabled.
|
||||
$this->drupalPostForm('webform/test_handler_test/test', ['element' => ''], t('Submit'), ['query' => ['_webform_handler' => 'debug']]);
|
||||
$this->assertNoRaw('One two one two this is just a test');
|
||||
$this->assertRaw("element: ''");
|
||||
|
||||
// Check 403 access denied for missing handler.
|
||||
$this->drupalGet('webform/test_handler_test/test', ['query' => ['_webform_handler' => 'missing']]);
|
||||
$this->assertResponse(403);
|
||||
$this->assertRaw('The <em class="placeholder">missing</em> email/handler for the <em class="placeholder">Test: Handler: Test invoke methods</em> webform does not exist.');
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -36,7 +36,7 @@ class WebformSettingsConfidentialTest extends WebformTestBase {
|
|||
|
||||
$this->drupalLogin($this->rootUser);
|
||||
|
||||
$webform_confidential = Webform::load('test_form_confidential');
|
||||
$webform = Webform::load('test_form_confidential');
|
||||
|
||||
// Check logout warning when accessing webform.
|
||||
$this->drupalGet('webform/test_form_confidential');
|
||||
|
@ -49,7 +49,7 @@ class WebformSettingsConfidentialTest extends WebformTestBase {
|
|||
$this->assertNoRaw('This form is confidential.');
|
||||
|
||||
// Check that test submission does not record the IP address.
|
||||
$sid = $this->postSubmissionTest($webform_confidential, ['name' => 'John']);
|
||||
$sid = $this->postSubmissionTest($webform, ['name' => 'John']);
|
||||
$webform_submission = WebformSubmission::load($sid);
|
||||
$this->assertEqual($webform_submission->getRemoteAddr(), t('(unknown)'));
|
||||
$this->assertEqual($webform_submission->getOwnerId(), 0);
|
||||
|
@ -61,7 +61,7 @@ class WebformSettingsConfidentialTest extends WebformTestBase {
|
|||
$this->assertNoRaw('This form is confidential.');
|
||||
|
||||
// Check that submission does not track the requests IP address.
|
||||
$sid = $this->postSubmission($webform_confidential, ['name' => 'John']);
|
||||
$sid = $this->postSubmission($webform, ['name' => 'John']);
|
||||
$webform_submission = WebformSubmission::load($sid);
|
||||
$this->assertEqual($webform_submission->getRemoteAddr(), t('(unknown)'));
|
||||
$this->assertEqual($webform_submission->getOwnerId(), 0);
|
||||
|
|
|
@ -79,12 +79,12 @@ class WebformSettingsConfirmationTest extends WebformTestBase {
|
|||
|
||||
// Check confirmation inline.
|
||||
$this->drupalPostForm('webform/test_confirmation_inline', [], t('Submit'));
|
||||
$this->assertRaw('<a href="' . $webform_confirmation_inline->toUrl('canonical', ['absolute' => TRUE])->toString() . '" rel="back" title="Back to form">Back to form</a>');
|
||||
$this->assertRaw('<a href="' . $webform_confirmation_inline->toUrl('canonical', ['absolute' => TRUE])->toString() . '" rel="prev" title="Back to form">Back to form</a>');
|
||||
$this->assertUrl('webform/test_confirmation_inline');
|
||||
|
||||
// Check confirmation inline with custom query parameters.
|
||||
$this->drupalPostForm('webform/test_confirmation_inline', [], t('Submit'), ['query' => ['custom' => 'param']]);
|
||||
$this->assertRaw('<a href="' . $webform_confirmation_inline->toUrl('canonical', ['absolute' => TRUE, 'query' => ['custom' => 'param']])->toString() . '" rel="back" title="Back to form">Back to form</a>');
|
||||
$this->assertRaw('<a href="' . $webform_confirmation_inline->toUrl('canonical', ['absolute' => TRUE, 'query' => ['custom' => 'param']])->toString() . '" rel="prev" title="Back to form">Back to form</a>');
|
||||
$this->assertUrl('webform/test_confirmation_inline', ['query' => ['custom' => 'param']]);
|
||||
|
||||
/* Test confirmation page (confirmation_type=page) */
|
||||
|
@ -95,7 +95,7 @@ class WebformSettingsConfirmationTest extends WebformTestBase {
|
|||
$sid = $this->postSubmission($webform_confirmation_page);
|
||||
$webform_submission = WebformSubmission::load($sid);
|
||||
$this->assertRaw('This is a custom confirmation page.');
|
||||
$this->assertRaw('<a href="' . $webform_confirmation_page->toUrl('canonical', ['absolute' => TRUE])->toString() . '" rel="back" title="Back to form">Back to form</a>');
|
||||
$this->assertRaw('<a href="' . $webform_confirmation_page->toUrl('canonical', ['absolute' => TRUE])->toString() . '" rel="prev" title="Back to form">Back to form</a>');
|
||||
$this->assertUrl('webform/test_confirmation_page/confirmation', ['query' => ['token' => $webform_submission->getToken()]]);
|
||||
|
||||
// Check that the confirmation page's 'Back to form 'link includes custom
|
||||
|
@ -130,13 +130,13 @@ class WebformSettingsConfirmationTest extends WebformTestBase {
|
|||
$this->postSubmission($webform_confirmation_page_custom);
|
||||
$this->assertRaw('<h1 class="page-title">Custom confirmation page title</h1>');
|
||||
$this->assertRaw('<div style="border: 10px solid red; padding: 1em;" class="webform-confirmation">');
|
||||
$this->assertRaw('<a href="' . $webform_confirmation_page_custom->toUrl()->setAbsolute()->toString() . '" rel="back" title="Custom back to link" class="button">Custom back to link</a>');
|
||||
$this->assertRaw('<a href="' . $webform_confirmation_page_custom->toUrl()->setAbsolute()->toString() . '" rel="prev" title="Custom back to link" class="button">Custom back to link</a>');
|
||||
|
||||
// Check back link is hidden.
|
||||
$webform_confirmation_page_custom->setSetting('confirmation_back', FALSE);
|
||||
$webform_confirmation_page_custom->save();
|
||||
$this->postSubmission($webform_confirmation_page_custom);
|
||||
$this->assertNoRaw('<a href="' . $webform_confirmation_page_custom->toUrl()->toString() . '" rel="back" title="Custom back to link" class="button">Custom back to link</a>');
|
||||
$this->assertNoRaw('<a href="' . $webform_confirmation_page_custom->toUrl()->toString() . '" rel="prev" title="Custom back to link" class="button">Custom back to link</a>');
|
||||
|
||||
/* Test confirmation URL (confirmation_type=url) */
|
||||
|
||||
|
|
|
@ -24,7 +24,7 @@ class WebformSettingsDraftTest extends WebformTestBase {
|
|||
* Test webform submission form draft.
|
||||
*/
|
||||
public function testDraft() {
|
||||
$normal_user = $this->drupalCreateUser();
|
||||
$normal_user = $this->drupalCreateUser(['view own webform submission']);
|
||||
|
||||
$admin_submission_user = $this->drupalCreateUser([
|
||||
'administer webform submission',
|
||||
|
|
|
@ -42,7 +42,7 @@ class WebformSettingsLimitUniqueTest extends WebformNodeTestBase {
|
|||
// Check that name is empty for new submission for admin user.
|
||||
$this->drupalLogin($admin_user);
|
||||
$this->drupalGet('webform/test_form_limit_total_unique');
|
||||
$this->assertFieldByName('name','');
|
||||
$this->assertFieldByName('name', '');
|
||||
|
||||
// Check that 'Test' form is available and display a message.
|
||||
$this->drupalGet('webform/test_form_limit_total_unique/test');
|
||||
|
@ -51,26 +51,26 @@ class WebformSettingsLimitUniqueTest extends WebformNodeTestBase {
|
|||
// Check that name is empty for new submission for root user.
|
||||
$this->drupalLogin($this->rootUser);
|
||||
$this->drupalGet('webform/test_form_limit_total_unique');
|
||||
$this->assertFieldByName('name','');
|
||||
$this->assertFieldByName('name', '');
|
||||
|
||||
// Check that name is set to 'John Smith' and 'Submission information' is
|
||||
// visible for admin user.
|
||||
$this->drupalLogin($admin_user);
|
||||
$sid = $this->postSubmission($webform_total_unique, ['name' => 'John Smith']);
|
||||
$this->drupalGet('webform/test_form_limit_total_unique');
|
||||
$this->assertFieldByName('name','John Smith');
|
||||
$this->assertFieldByName('name', 'John Smith');
|
||||
$this->assertRaw("<div><b>Submission ID:</b> $sid</div>");
|
||||
|
||||
// Check that name is set to 'John Smith' and 'Submission information' is
|
||||
// visible for root user.
|
||||
$this->drupalGet('webform/test_form_limit_total_unique');
|
||||
$this->assertFieldByName('name','John Smith');
|
||||
$this->assertFieldByName('name', 'John Smith');
|
||||
$this->assertRaw("<div><b>Submission ID:</b> $sid</div>");
|
||||
|
||||
// Check that 'Test' form also has name set to 'John Smith'
|
||||
// and does not display a message.
|
||||
$this->drupalGet('webform/test_form_limit_total_unique/test');
|
||||
$this->assertFieldByName('name','John Smith');
|
||||
$this->assertFieldByName('name', 'John Smith');
|
||||
$this->assertRaw("<div><b>Submission ID:</b> $sid</div>");
|
||||
$this->assertNoRaw(' The below webform has been prepopulated with custom/random test data. When submitted, this information <strong>will still be saved</strong> and/or <strong>sent to designated recipients</strong>');
|
||||
|
||||
|
@ -85,26 +85,26 @@ class WebformSettingsLimitUniqueTest extends WebformNodeTestBase {
|
|||
|
||||
// Check that name is empty for new submission for admin user.
|
||||
$this->drupalGet('node/' . $node_total_unique->id());
|
||||
$this->assertFieldByName('name','');
|
||||
$this->assertFieldByName('name', '');
|
||||
|
||||
// Check that name is set to 'John Lennon' and 'Submission information' is
|
||||
// visible for admin user.
|
||||
$sid = $this->postNodeSubmission($node_total_unique, ['name' => 'John Lennon']);
|
||||
$this->drupalGet('webform/test_form_limit_total_unique');
|
||||
$this->assertFieldByName('name','John Lennon');
|
||||
$this->assertFieldByName('name', 'John Lennon');
|
||||
$this->assertRaw("<div><b>Submission ID:</b> $sid</div>");
|
||||
|
||||
// Check that 'Test' form also has name set to 'John Lennon'
|
||||
// and does not display a message.
|
||||
$this->drupalGet('/node/' . $node_total_unique->id() . '/webform/test');
|
||||
$this->assertFieldByName('name','John Lennon');
|
||||
$this->assertFieldByName('name', 'John Lennon');
|
||||
$this->assertRaw("<div><b>Submission ID:</b> $sid</div>");
|
||||
|
||||
// Check that 'Test' form also has name set to 'John Lennon'
|
||||
// and does not display a message for root user
|
||||
// and does not display a message for root user.
|
||||
$this->drupalLogin($this->rootUser);
|
||||
$this->drupalGet('/node/' . $node_total_unique->id() . '/webform/test');
|
||||
$this->assertFieldByName('name','John Lennon');
|
||||
$this->assertFieldByName('name', 'John Lennon');
|
||||
$this->assertRaw("<div><b>Submission ID:</b> $sid</div>");
|
||||
|
||||
/**************************************************************************/
|
||||
|
@ -114,7 +114,7 @@ class WebformSettingsLimitUniqueTest extends WebformNodeTestBase {
|
|||
// Check that name is empty for new submission for admin user.
|
||||
$this->drupalLogin($admin_user);
|
||||
$this->drupalGet('webform/test_form_limit_user_unique');
|
||||
$this->assertFieldByName('name','');
|
||||
$this->assertFieldByName('name', '');
|
||||
|
||||
// Check that 'Test' form is available and display a message.
|
||||
$this->drupalGet('webform/test_form_limit_user_unique/test');
|
||||
|
@ -123,20 +123,20 @@ class WebformSettingsLimitUniqueTest extends WebformNodeTestBase {
|
|||
// Check that name is empty for new submission for root user.
|
||||
$this->drupalLogin($this->rootUser);
|
||||
$this->drupalGet('webform/test_form_limit_user_unique');
|
||||
$this->assertFieldByName('name','');
|
||||
$this->assertFieldByName('name', '');
|
||||
|
||||
// Check that name is set to 'John Smith' and 'Submission information' is
|
||||
// visible for admin user.
|
||||
$this->drupalLogin($admin_user);
|
||||
$sid = $this->postSubmission($webform_user_unique, ['name' => 'John Smith']);
|
||||
$this->drupalGet('webform/test_form_limit_user_unique');
|
||||
$this->assertFieldByName('name','John Smith');
|
||||
$this->assertFieldByName('name', 'John Smith');
|
||||
$this->assertRaw("<div><b>Submission ID:</b> $sid</div>");
|
||||
|
||||
// Check that 'Test' form also has name set to 'John Smith'
|
||||
// and does not display a message.
|
||||
$this->drupalGet('webform/test_form_limit_user_unique/test');
|
||||
$this->assertFieldByName('name','John Smith');
|
||||
$this->assertFieldByName('name', 'John Smith');
|
||||
$this->assertRaw("<div><b>Submission ID:</b> $sid</div>");
|
||||
|
||||
/**************************************************************************/
|
||||
|
@ -144,19 +144,19 @@ class WebformSettingsLimitUniqueTest extends WebformNodeTestBase {
|
|||
// Check that name is still empty for new submission for root user.
|
||||
$this->drupalLogin($this->rootUser);
|
||||
$this->drupalGet('webform/test_form_limit_user_unique');
|
||||
$this->assertFieldByName('name','');
|
||||
$this->assertFieldByName('name', '');
|
||||
|
||||
// Check that name is set to 'John Smith' and 'Submission information' is
|
||||
// visible for root user.
|
||||
$sid = $this->postSubmission($webform_user_unique, ['name' => 'Jane Doe']);
|
||||
$this->drupalGet('webform/test_form_limit_user_unique');
|
||||
$this->assertFieldByName('name','Jane Doe');
|
||||
$this->assertFieldByName('name', 'Jane Doe');
|
||||
$this->assertRaw("<div><b>Submission ID:</b> $sid</div>");
|
||||
|
||||
// Check that 'Test' form also has name set to 'Jane Doe'
|
||||
// and does not display a message.
|
||||
$this->drupalGet('webform/test_form_limit_user_unique/test');
|
||||
$this->assertFieldByName('name','Jane Doe');
|
||||
$this->assertFieldByName('name', 'Jane Doe');
|
||||
$this->assertRaw("<div><b>Submission ID:</b> $sid</div>");
|
||||
|
||||
}
|
||||
|
|
|
@ -20,6 +20,9 @@ class WebformSettingsPathTest extends WebformTestBase {
|
|||
* Tests YAML page and title.
|
||||
*/
|
||||
public function testPaths() {
|
||||
/** @var \Drupal\Core\Path\AliasStorageInterface $alias_storage */
|
||||
$alias_storage = $this->container->get('path.alias_storage');
|
||||
|
||||
$node = $this->drupalCreateNode();
|
||||
|
||||
$webform = Webform::create([
|
||||
|
@ -32,39 +35,68 @@ class WebformSettingsPathTest extends WebformTestBase {
|
|||
]),
|
||||
]);
|
||||
$webform->save();
|
||||
$webform_path = '/webform/' . $webform->id();
|
||||
$form_path = '/form/' . str_replace('_', '-', $webform->id());
|
||||
|
||||
// Check paths.
|
||||
$this->drupalLogin($this->rootUser);
|
||||
|
||||
// Check that aliases exist.
|
||||
$this->assert(is_array($alias_storage->load(['alias' => $form_path])));
|
||||
$this->assert(is_array($alias_storage->load(['alias' => "$form_path/confirmation"])));
|
||||
$this->assert(is_array($alias_storage->load(['alias' => "$form_path/drafts"])));
|
||||
$this->assert(is_array($alias_storage->load(['alias' => "$form_path/submissions"])));
|
||||
|
||||
// Check default system submit path.
|
||||
$this->drupalGet('webform/' . $webform->id());
|
||||
$this->drupalGet($webform_path);
|
||||
$this->assertResponse(200, 'Submit system path exists');
|
||||
|
||||
// Check default alias submit path.
|
||||
$this->drupalGet('form/' . str_replace('_', '-', $webform->id()));
|
||||
$this->drupalGet($form_path);
|
||||
$this->assertResponse(200, 'Submit URL alias exists');
|
||||
|
||||
// Check default alias confirm path.
|
||||
$this->drupalGet('form/' . str_replace('_', '-', $webform->id()) . '/confirmation');
|
||||
$this->drupalGet("$form_path/confirmation");
|
||||
$this->assertResponse(200, 'Confirm URL alias exists');
|
||||
|
||||
// Check page hidden (i.e. access denied).
|
||||
// Check default alias drafts path.
|
||||
$this->drupalGet("$form_path/drafts");
|
||||
$this->assertResponse(200, 'Drafts URL alias exists');
|
||||
|
||||
// Check default alias submissions path.
|
||||
$this->drupalGet("$form_path/submissions");
|
||||
$this->assertResponse(200, 'Submissions URL alias exists');
|
||||
|
||||
$this->drupalLogout();
|
||||
|
||||
// Disable paths for the webform.
|
||||
$webform->setSettings(['page' => FALSE])->save();
|
||||
$this->drupalGet('webform/' . $webform->id());
|
||||
|
||||
// Check that aliases do not exist.
|
||||
$this->assertFalse($alias_storage->load(['alias' => $form_path]));
|
||||
$this->assertFalse($alias_storage->load(['alias' => "$form_path/confirmation"]));
|
||||
$this->assertFalse($alias_storage->load(['alias' => "$form_path/drafts"]));
|
||||
$this->assertFalse($alias_storage->load(['alias' => "$form_path/submissions"]));
|
||||
|
||||
// Check page hidden (i.e. access denied).
|
||||
$this->drupalGet($webform_path);
|
||||
$this->assertResponse(403, 'Submit system path access denied');
|
||||
$this->assertNoRaw('Only webform administrators are allowed to access this page and create new submissions.');
|
||||
$this->drupalGet('form/' . str_replace('_', '-', $webform->id()));
|
||||
$this->drupalGet($form_path);
|
||||
$this->assertResponse(404, 'Submit URL alias does not exist');
|
||||
|
||||
// Check page hidden with source entity.
|
||||
$this->drupalGet('webform/' . $webform->id(), ['query' => ['source_entity_type' => 'node', 'source_entity_id' => $node->id()]]);
|
||||
$this->drupalGet($webform_path, ['query' => ['source_entity_type' => 'node', 'source_entity_id' => $node->id()]]);
|
||||
$this->assertResponse(403, 'Submit system path access denied');
|
||||
|
||||
// Check page visible with source entity.
|
||||
$webform->setSettings(['form_prepopulate_source_entity' => TRUE])->save();
|
||||
$this->drupalGet('webform/' . $webform->id(), ['query' => ['source_entity_type' => 'node', 'source_entity_id' => $node->id()]]);
|
||||
$this->drupalGet($webform_path, ['query' => ['source_entity_type' => 'node', 'source_entity_id' => $node->id()]]);
|
||||
$this->assertResponse(200, 'Submit system path exists');
|
||||
|
||||
// Check hidden page visible to admin.
|
||||
$this->drupalLogin($this->rootUser);
|
||||
$this->drupalGet('webform/' . $webform->id());
|
||||
$this->drupalGet($webform_path);
|
||||
$this->assertResponse(200, 'Submit system path access permitted');
|
||||
$this->assertRaw('Only webform administrators are allowed to access this page and create new submissions.');
|
||||
$this->drupalLogout();
|
||||
|
@ -107,13 +139,15 @@ class WebformSettingsPathTest extends WebformTestBase {
|
|||
]),
|
||||
]);
|
||||
$webform->save();
|
||||
$webform_path = '/webform/' . $webform->id();
|
||||
$form_path = '/form/' . str_replace('_', '-', $webform->id());
|
||||
|
||||
// Check default system submit path.
|
||||
$this->drupalGet('webform/' . $webform->id());
|
||||
$this->drupalGet($webform_path);
|
||||
$this->assertResponse(200, 'Submit system path exists');
|
||||
|
||||
// Check no default alias submit path.
|
||||
$this->drupalGet('form/' . str_replace('_', '-', $webform->id()));
|
||||
$this->drupalGet($form_path);
|
||||
$this->assertResponse(404, 'Submit URL alias does not exist');
|
||||
|
||||
}
|
||||
|
|
|
@ -92,6 +92,13 @@ class WebformSettingsPrepopulateTest extends WebformTestBase {
|
|||
$this->drupalGet('webform/test_form_prepopulate', ['query' => ['source_entity_type' => 'webform', 'source_entity_id' => 'contact']]);
|
||||
$this->assertNoRaw('This webform is not available. Please contact the site administrator.');
|
||||
|
||||
// Check that required prepopulated source entity can be updated (edit).
|
||||
$this->drupalLogin($this->rootUser);
|
||||
$sid = $this->postSubmission($webform_prepopulate, [], t('Submit'), ['query' => ['source_entity_type' => 'webform', 'source_entity_id' => 'contact']]);
|
||||
$this->drupalGet("/admin/structure/webform/manage/test_form_prepopulate/submission/$sid/edit");
|
||||
$this->assertNoRaw('This webform is not available. Please contact the site administrator.');
|
||||
$this->drupalLogout();
|
||||
|
||||
// Set prepopulated source entity type to user.
|
||||
$webform_prepopulate->setSetting('form_prepopulate_source_entity_type', 'user');
|
||||
$webform_prepopulate->save();
|
||||
|
|
|
@ -49,15 +49,24 @@ class WebformSettingsPreviewTest extends WebformTestBase {
|
|||
$this->drupalPostForm('webform/test_form_preview', ['name' => 'test', 'email' => 'example@example.com', 'checkbox' => TRUE], t('Preview'));
|
||||
|
||||
$this->assertRaw('<h1 class="page-title">Test: Webform: Preview: Preview</h1>');
|
||||
|
||||
$this->assertRaw('<b>Preview</b></li>');
|
||||
|
||||
$this->assertRaw('Please review your submission. Your submission is not complete until you press the "Submit" button!');
|
||||
|
||||
$this->assertFieldByName('op', 'Submit');
|
||||
$this->assertFieldByName('op', '< Previous');
|
||||
$this->assertRaw('<div id="test_form_preview--name" class="webform-element webform-element-type-textfield js-form-item form-item js-form-type-item form-type-item js-form-item-name form-item-name">');
|
||||
|
||||
$this->assertRaw('<div class="webform-preview js-form-wrapper form-wrapper" data-drupal-selector="edit-preview" id="edit-preview"><fieldset class="format-attributes-class webform-container webform-container-type-fieldset js-form-item form-item js-form-wrapper form-wrapper" id="test_form_preview--fieldset">');
|
||||
$this->assertRaw('<div class="format-attributes-class webform-element webform-element-type-textfield js-form-item form-item js-form-type-item form-type-item js-form-item-name form-item-name" id="test_form_preview--name">');
|
||||
$this->assertRaw('<label>Name</label>' . PHP_EOL . ' test');
|
||||
$this->assertRaw('<div id="test_form_preview--email" class="webform-element webform-element-type-email js-form-item form-item js-form-type-item form-type-item js-form-item-email form-item-email">');
|
||||
|
||||
$this->assertRaw('<section class="format-attributes-class js-form-item form-item js-form-wrapper form-wrapper webform-section" id="test_form_preview--container">');
|
||||
$this->assertRaw('<div class="format-attributes-class webform-element webform-element-type-email js-form-item form-item js-form-type-item form-type-item js-form-item-email form-item-email" id="test_form_preview--email">');
|
||||
$this->assertRaw('<label>Email</label>' . PHP_EOL . ' <a href="mailto:example@example.com">example@example.com</a>');
|
||||
$this->assertRaw('<div id="test_form_preview--checkbox" class="webform-element webform-element-type-checkbox js-form-item form-item js-form-type-item form-type-item js-form-item-checkbox form-item-checkbox">');
|
||||
|
||||
$this->assertRaw('<div class="format-attributes-class webform-element webform-element-type-checkbox js-form-item form-item js-form-type-item form-type-item js-form-item-checkbox form-item-checkbox" id="test_form_preview--checkbox">');
|
||||
$this->assertRaw('<section class="format-attributes-class js-form-item form-item js-form-wrapper form-wrapper webform-section" id="test_form_preview--section">');
|
||||
$this->assertRaw('<label>Checkbox</label>' . PHP_EOL . ' Yes');
|
||||
$this->assertRaw('<div class="webform-preview js-form-wrapper form-wrapper" data-drupal-selector="edit-preview" id="edit-preview">');
|
||||
|
||||
|
@ -100,7 +109,7 @@ class WebformSettingsPreviewTest extends WebformTestBase {
|
|||
// Check empty elements are included in preview.
|
||||
$this->drupalPostForm('webform/test_form_preview', ['name' => '', 'email' => '', 'checkbox' => FALSE], t('Preview'));
|
||||
$this->assertRaw('<label>Name</label>' . PHP_EOL . ' {Empty}');
|
||||
$this->assertRaw('<div id="test_form_preview--email" class="webform-element webform-element-type-email js-form-item form-item js-form-type-item form-type-item js-form-item-email form-item-email">');
|
||||
$this->assertRaw('<div class="format-attributes-class webform-element webform-element-type-email js-form-item form-item js-form-type-item form-type-item js-form-item-email form-item-email" id="test_form_preview--email">');
|
||||
$this->assertRaw('<label>Email</label>' . PHP_EOL . ' {Empty}');
|
||||
$this->assertRaw('<label>Checkbox</label>' . PHP_EOL . ' No');
|
||||
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Reference in a new issue