Webform module and config export
This commit is contained in:
parent
3e6a5cbed2
commit
0e15467384
1040 changed files with 117682 additions and 0 deletions
146
web/modules/contrib/webform/src/Access/WebformAccess.php
Normal file
146
web/modules/contrib/webform/src/Access/WebformAccess.php
Normal file
|
|
@ -0,0 +1,146 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\webform\Access;
|
||||
|
||||
use Drupal\Core\Access\AccessResult;
|
||||
use Drupal\Core\Entity\EntityInterface;
|
||||
use Drupal\Core\Session\AccountInterface;
|
||||
use Drupal\webform\Plugin\Field\FieldType\WebformEntityReferenceItem;
|
||||
use Drupal\webform\WebformHandlerMessageInterface;
|
||||
use Drupal\webform\WebformInterface;
|
||||
use Drupal\webform\WebformSubmissionInterface;
|
||||
|
||||
/**
|
||||
* Defines the custom access control handler for the webform entities.
|
||||
*/
|
||||
class WebformAccess {
|
||||
|
||||
/**
|
||||
* Check whether the webform has results.
|
||||
*
|
||||
* @param \Drupal\webform\WebformInterface $webform
|
||||
* A webform.
|
||||
* @param \Drupal\Core\Entity\EntityInterface|null $source_entity
|
||||
* The source entity.
|
||||
*
|
||||
* @return \Drupal\Core\Access\AccessResultInterface
|
||||
* The access result.
|
||||
*/
|
||||
public static function checkResultsAccess(WebformInterface $webform, EntityInterface $source_entity = NULL) {
|
||||
// If results are not disabled return neutral.
|
||||
if (!$webform->getSetting('results_disabled')) {
|
||||
$access_result = AccessResult::allowed();
|
||||
}
|
||||
// If webform has any results return neutral.
|
||||
elseif (\Drupal::entityTypeManager()->getStorage('webform_submission')->getTotal($webform, $source_entity)) {
|
||||
$access_result = AccessResult::allowed();
|
||||
}
|
||||
// Finally, forbid access to the results.
|
||||
else {
|
||||
$access_result = AccessResult::forbidden();
|
||||
}
|
||||
return $access_result->addCacheableDependency($webform);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether the user has 'administer webform' or 'administer webform submission' permission.
|
||||
*
|
||||
* @param \Drupal\Core\Session\AccountInterface $account
|
||||
* Run access checks for this account.
|
||||
*
|
||||
* @return \Drupal\Core\Access\AccessResultInterface
|
||||
* The access result.
|
||||
*/
|
||||
public static function checkAdminAccess(AccountInterface $account) {
|
||||
return AccessResult::allowedIf($account->hasPermission('administer webform') || $account->hasPermission('administer webform submission'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether the user can view submissions.
|
||||
*
|
||||
* @param \Drupal\Core\Session\AccountInterface $account
|
||||
* Run access checks for this account.
|
||||
*
|
||||
* @return \Drupal\Core\Access\AccessResultInterface
|
||||
* The access result.
|
||||
*/
|
||||
public static function checkSubmissionAccess(AccountInterface $account) {
|
||||
return AccessResult::allowedIf($account->hasPermission('administer webform') || $account->hasPermission('administer webform submission') || $account->hasPermission('view any webform submission'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether the user has 'administer' or 'overview' permission.
|
||||
*
|
||||
* @param \Drupal\Core\Session\AccountInterface $account
|
||||
* Run access checks for this account.
|
||||
*
|
||||
* @return \Drupal\Core\Access\AccessResultInterface
|
||||
* The access result.
|
||||
*/
|
||||
public static function checkOverviewAccess(AccountInterface $account) {
|
||||
return AccessResult::allowedIf($account->hasPermission('administer webform') || $account->hasPermission('administer webform submission') || $account->hasPermission('access webform overview'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Check that webform submission has email and the user can update any webform submission.
|
||||
*
|
||||
* @param \Drupal\webform\WebformSubmissionInterface $webform_submission
|
||||
* A webform submission.
|
||||
* @param \Drupal\Core\Session\AccountInterface $account
|
||||
* Run access checks for this account.
|
||||
*
|
||||
* @return \Drupal\Core\Access\AccessResultInterface
|
||||
* The access result.
|
||||
*/
|
||||
public static function checkEmailAccess(WebformSubmissionInterface $webform_submission, AccountInterface $account) {
|
||||
$webform = $webform_submission->getWebform();
|
||||
if ($webform->access('submission_update_any', $account)) {
|
||||
$handlers = $webform->getHandlers();
|
||||
foreach ($handlers as $handler) {
|
||||
if ($handler instanceof WebformHandlerMessageInterface) {
|
||||
return AccessResult::allowed();
|
||||
}
|
||||
}
|
||||
}
|
||||
return AccessResult::forbidden();
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether the user can access an entity's webform results.
|
||||
*
|
||||
* @param \Drupal\Core\Entity\EntityInterface $entity
|
||||
* An entity.
|
||||
* @param \Drupal\Core\Session\AccountInterface $account
|
||||
* Run access checks for this account.
|
||||
*
|
||||
* @return \Drupal\Core\Access\AccessResultInterface
|
||||
* The access result.
|
||||
*/
|
||||
public static function checkEntityResultsAccess(EntityInterface $entity, AccountInterface $account) {
|
||||
$webform_field_name = WebformEntityReferenceItem::getEntityWebformFieldName($entity);
|
||||
return AccessResult::allowedIf($entity->access('update', $account) && $webform_field_name && $entity->$webform_field_name->entity);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether the webform has wizard pages.
|
||||
*
|
||||
* @param \Drupal\webform\WebformInterface $webform
|
||||
* A webform.
|
||||
*
|
||||
* @return \Drupal\Core\Access\AccessResultInterface
|
||||
* The access result.
|
||||
*
|
||||
* @see \Drupal\webform\WebformSubmissionForm::buildForm
|
||||
* @see \Drupal\webform\Entity\Webform::getPages
|
||||
*/
|
||||
public static function checkWebformWizardPagesAccess(WebformInterface $webform) {
|
||||
$elements = $webform->getElementsInitialized();
|
||||
foreach ($elements as $key => $element) {
|
||||
if (isset($element['#type']) && $element['#type'] == 'webform_wizard_page') {
|
||||
return AccessResult::allowed();
|
||||
}
|
||||
}
|
||||
return AccessResult::forbidden();
|
||||
}
|
||||
|
||||
}
|
||||
41
web/modules/contrib/webform/src/Ajax/ScrollTopCommand.php
Normal file
41
web/modules/contrib/webform/src/Ajax/ScrollTopCommand.php
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\webform\Ajax;
|
||||
|
||||
use Drupal\Core\Ajax\CommandInterface;
|
||||
|
||||
/**
|
||||
* Provides an AJAX command for scrolling to the top of an element.
|
||||
*
|
||||
* This command is implemented in Drupal.AjaxCommands.prototype.webformScrollTop.
|
||||
*/
|
||||
class ScrollTopCommand implements CommandInterface {
|
||||
|
||||
/**
|
||||
* A CSS selector string.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $selector;
|
||||
|
||||
/**
|
||||
* Constructs a \Drupal\webform\Ajax\ScrollTopCommand object.
|
||||
*
|
||||
* @param string $selector
|
||||
* A CSS selector.
|
||||
*/
|
||||
public function __construct($selector) {
|
||||
$this->selector = $selector;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function render() {
|
||||
return [
|
||||
'command' => 'webformScrollTop',
|
||||
'selector' => $this->selector,
|
||||
];
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,97 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\webform\Annotation;
|
||||
|
||||
use Drupal\Component\Annotation\Plugin;
|
||||
|
||||
/**
|
||||
* Defines a webform element annotation object.
|
||||
*
|
||||
* Plugin Namespace: Plugin\WebformElement.
|
||||
*
|
||||
* For a working example, see
|
||||
* \Drupal\webform\Plugin\WebformElement\Email
|
||||
*
|
||||
* @see hook_webform_element_info_alter()
|
||||
* @see \Drupal\webform\WebformElementInterface
|
||||
* @see \Drupal\webform\WebformElementBase
|
||||
* @see \Drupal\webform\WebformElementManager
|
||||
* @see \Drupal\webform\WebformElementManagerInterface
|
||||
* @see plugin_api
|
||||
*
|
||||
* @Annotation
|
||||
*/
|
||||
class WebformElement extends Plugin {
|
||||
|
||||
/**
|
||||
* The plugin ID.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $id;
|
||||
|
||||
/**
|
||||
* URL to the element's API documentation.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $api;
|
||||
|
||||
/**
|
||||
* The human-readable name of the webform element.
|
||||
*
|
||||
* @var \Drupal\Core\Annotation\Translation
|
||||
*
|
||||
* @ingroup plugin_translatable
|
||||
*/
|
||||
public $label;
|
||||
|
||||
/**
|
||||
* The category in the admin UI where the webform will be listed.
|
||||
*
|
||||
* @var \Drupal\Core\Annotation\Translation
|
||||
*
|
||||
* @ingroup plugin_translatable
|
||||
*/
|
||||
public $category = '';
|
||||
|
||||
/**
|
||||
* A brief description of the webform element.
|
||||
*
|
||||
* This will be shown when adding or configuring this webform element.
|
||||
*
|
||||
* @var \Drupal\Core\Annotation\Translation
|
||||
*
|
||||
* @ingroup plugin_translatable
|
||||
*/
|
||||
public $description = '';
|
||||
|
||||
/**
|
||||
* Flag that defines hidden element.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
public $hidden = FALSE;
|
||||
|
||||
/**
|
||||
* Flag that defines multiline element.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
public $multiline = FALSE;
|
||||
|
||||
/**
|
||||
* Flag that defines composite element.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
public $composite = FALSE;
|
||||
|
||||
/**
|
||||
* Flag that defines if #states wrapper should applied be to the element.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
public $states_wrapper = FALSE;
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,75 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\webform\Annotation;
|
||||
|
||||
use Drupal\Component\Annotation\Plugin;
|
||||
|
||||
/**
|
||||
* Defines a results exporter annotation object.
|
||||
*
|
||||
* Plugin Namespace: Plugin\WebformExporter.
|
||||
*
|
||||
* For a working example, see
|
||||
* \Drupal\webform\Plugin\WebformExporter\DelimitedText/WebformExporter
|
||||
*
|
||||
* @see hook_webform_exporter_info_alter()
|
||||
* @see \Drupal\webform\WebformExporterInterface
|
||||
* @see \Drupal\webform\WebformExporterBase
|
||||
* @see \Drupal\webform\WebformExporterManager
|
||||
* @see plugin_api
|
||||
*
|
||||
* @Annotation
|
||||
*/
|
||||
class WebformExporter extends Plugin {
|
||||
|
||||
/**
|
||||
* The plugin ID.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $id;
|
||||
|
||||
/**
|
||||
* The human-readable name of the results exporter.
|
||||
*
|
||||
* @var \Drupal\Core\Annotation\Translation
|
||||
*
|
||||
* @ingroup plugin_translatable
|
||||
*/
|
||||
public $label;
|
||||
|
||||
/**
|
||||
* The category in the admin UI where the block will be listed.
|
||||
*
|
||||
* @var \Drupal\Core\Annotation\Translation
|
||||
*
|
||||
* @ingroup plugin_translatable
|
||||
*/
|
||||
public $category = '';
|
||||
|
||||
/**
|
||||
* A brief description of the results exporter.
|
||||
*
|
||||
* This will be shown when adding or configuring this results exporter.
|
||||
*
|
||||
* @var \Drupal\Core\Annotation\Translation
|
||||
*
|
||||
* @ingroup plugin_translatable
|
||||
*/
|
||||
public $description = '';
|
||||
|
||||
/**
|
||||
* Generates zipped archive.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
public $archive = FALSE;
|
||||
|
||||
/**
|
||||
* Using export options.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
public $options = TRUE;
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,82 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\webform\Annotation;
|
||||
|
||||
use Drupal\Component\Annotation\Plugin;
|
||||
use Drupal\webform\WebformHandlerInterface;
|
||||
|
||||
/**
|
||||
* Defines a webform handler annotation object.
|
||||
*
|
||||
* Plugin Namespace: Plugin\WebformHandler.
|
||||
*
|
||||
* For a working example, see
|
||||
* \Drupal\webform\Plugin\WebformHandler\EmailWebformHandler
|
||||
*
|
||||
* @see hook_webform_handler_info_alter()
|
||||
* @see \Drupal\webform\WebformHandlerInterface
|
||||
* @see \Drupal\webform\WebformHandlerBase
|
||||
* @see \Drupal\webform\WebformHandlerManager
|
||||
* @see plugin_api
|
||||
*
|
||||
* @Annotation
|
||||
*/
|
||||
class WebformHandler extends Plugin {
|
||||
|
||||
/**
|
||||
* The plugin ID.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $id;
|
||||
|
||||
/**
|
||||
* The human-readable name of the webform handler.
|
||||
*
|
||||
* @var \Drupal\Core\Annotation\Translation
|
||||
*
|
||||
* @ingroup plugin_translatable
|
||||
*/
|
||||
public $label;
|
||||
|
||||
/**
|
||||
* The category in the admin UI where the block will be listed.
|
||||
*
|
||||
* @var \Drupal\Core\Annotation\Translation
|
||||
*
|
||||
* @ingroup plugin_translatable
|
||||
*/
|
||||
public $category = '';
|
||||
|
||||
/**
|
||||
* A brief description of the webform handler.
|
||||
*
|
||||
* This will be shown when adding or configuring this webform handler.
|
||||
*
|
||||
* @var \Drupal\Core\Annotation\Translation
|
||||
*
|
||||
* @ingroup plugin_translatable
|
||||
*/
|
||||
public $description = '';
|
||||
|
||||
/**
|
||||
* The maximum number of instances allowed for this webform handler.
|
||||
*
|
||||
* Possible values are positive integers or
|
||||
* \Drupal\webform\WebformHandlerInterface::CARDINALITY_UNLIMITED or
|
||||
* \Drupal\webform\WebformHandlerInterface::CARDINALITY_SINGLE.
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
public $cardinality = WebformHandlerInterface::CARDINALITY_UNLIMITED;
|
||||
|
||||
/**
|
||||
* Notifies the webform that this handler processes results.
|
||||
*
|
||||
* When set to TRUE, 'Disable saving of submissions.' can be set.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
public $results = WebformHandlerInterface::RESULTS_IGNORED;
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,206 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\webform\BreadCrumb;
|
||||
|
||||
use Drupal\Core\Breadcrumb\BreadcrumbBuilderInterface;
|
||||
use Drupal\Core\Breadcrumb\Breadcrumb;
|
||||
use Drupal\Core\Extension\ModuleHandlerInterface;
|
||||
use Drupal\Core\Link;
|
||||
use Drupal\Core\Routing\RouteMatchInterface;
|
||||
use Drupal\Core\StringTranslation\StringTranslationTrait;
|
||||
use Drupal\Core\StringTranslation\TranslationInterface;
|
||||
use Drupal\Core\Url;
|
||||
use Drupal\webform\WebformInterface;
|
||||
use Drupal\webform\WebformRequestInterface;
|
||||
use Drupal\webform\WebformSubmissionInterface;
|
||||
|
||||
/**
|
||||
* Provides a webform breadcrumb builder.
|
||||
*/
|
||||
class WebformBreadcrumbBuilder implements BreadcrumbBuilderInterface {
|
||||
|
||||
use StringTranslationTrait;
|
||||
|
||||
/**
|
||||
* The current route's entity or plugin type.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $type;
|
||||
|
||||
/**
|
||||
* Webform request handler.
|
||||
*
|
||||
* @var \Drupal\webform\WebformRequestInterface
|
||||
*/
|
||||
protected $requestHandler;
|
||||
|
||||
/**
|
||||
* The module handler service.
|
||||
*
|
||||
* @var \Drupal\Core\Extension\ModuleHandlerInterface
|
||||
*/
|
||||
protected $moduleHandler;
|
||||
|
||||
/**
|
||||
* Constructs a WebformBreadcrumbBuilder.
|
||||
*
|
||||
* @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler
|
||||
* The module handler service.
|
||||
* @param \Drupal\webform\WebformRequestInterface $request_handler
|
||||
* The webform request handler.
|
||||
* @param \Drupal\Core\StringTranslation\TranslationInterface $string_translation
|
||||
* The string translation service.
|
||||
*/
|
||||
public function __construct(ModuleHandlerInterface $module_handler, WebformRequestInterface $request_handler, TranslationInterface $string_translation) {
|
||||
$this->moduleHandler = $module_handler;
|
||||
$this->requestHandler = $request_handler;
|
||||
$this->setStringTranslation($string_translation);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function applies(RouteMatchInterface $route_match) {
|
||||
$route_name = $route_match->getRouteName();
|
||||
// All routes must begin or contain 'webform.
|
||||
if (strpos($route_name, 'webform') === FALSE) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
$args = explode('.', $route_name);
|
||||
|
||||
// Skip all config_translation routes except the overview
|
||||
// and allow Drupal to use the path as the breadcrumb.
|
||||
if (strpos($route_name, 'config_translation') !== FALSE && $route_name != 'entity.webform.config_translation_overview') {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
try {
|
||||
$path = Url::fromRouteMatch($route_match)->toString();
|
||||
$base_path = base_path();
|
||||
}
|
||||
catch (\Exception $exception) {
|
||||
$path = '';
|
||||
$base_path = '/';
|
||||
}
|
||||
if ((count($args) > 2) && $args[0] == 'entity' && ($args[2] == 'webform' || $args[2] == 'webform_submission')) {
|
||||
$this->type = 'webform_source_entity';
|
||||
}
|
||||
elseif (strpos($route_name, 'entity.webform_ui.element') === 0) {
|
||||
$this->type = 'webform_element';
|
||||
}
|
||||
elseif (strpos($route_name, 'entity.webform.handler.') === 0) {
|
||||
$this->type = 'webform_handler';
|
||||
}
|
||||
elseif ($route_match->getParameter('webform_submission') instanceof WebformSubmissionInterface && strpos($route_name, 'webform.user.submission') !== FALSE) {
|
||||
$this->type = 'webform_user_submission';
|
||||
}
|
||||
elseif (strpos($route_match->getRouteName(), 'webform.user.submissions') !== FALSE) {
|
||||
$this->type = 'webform_user_submissions';
|
||||
}
|
||||
elseif ($route_match->getParameter('webform_submission') instanceof WebformSubmissionInterface && $route_match->getParameter('webform_submission')->access('admin')) {
|
||||
$this->type = 'webform_submission';
|
||||
}
|
||||
elseif (($route_match->getParameter('webform') instanceof WebformInterface && $route_match->getParameter('webform')->access('admin'))) {
|
||||
/** @var \Drupal\webform\WebformInterface $webform */
|
||||
$webform = $route_match->getParameter('webform');
|
||||
$this->type = ($webform->isTemplate() && $this->moduleHandler->moduleExists('webform_templates')) ? 'webform_template' : 'webform';
|
||||
}
|
||||
elseif (strpos($path, $base_path . 'admin/structure/webform/test/') === 0) {
|
||||
$this->type = 'webform_test';
|
||||
}
|
||||
else {
|
||||
$this->type = NULL;
|
||||
}
|
||||
|
||||
return ($this->type) ? TRUE : FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function build(RouteMatchInterface $route_match) {
|
||||
if ($this->type == 'webform_source_entity') {
|
||||
$source_entity = $this->requestHandler->getCurrentSourceEntity(['webform', 'webform_submission']);
|
||||
$entity_type = $source_entity->getEntityTypeId();
|
||||
$entity_id = $source_entity->id();
|
||||
|
||||
$breadcrumb = new Breadcrumb();
|
||||
$breadcrumb->addLink(Link::createFromRoute($this->t('Home'), '<front>'));
|
||||
$breadcrumb->addLink($source_entity->toLink());
|
||||
if ($webform_submission = $route_match->getParameter('webform_submission')) {
|
||||
if (strpos($route_match->getRouteName(), 'webform.user.submission') !== FALSE) {
|
||||
$breadcrumb->addLink(Link::createFromRoute($this->t('Submissions'), "entity.$entity_type.webform.user.submissions", [$entity_type => $entity_id]));
|
||||
}
|
||||
elseif ($source_entity->access('webform_submission_view') || $webform_submission->access('view_any')) {
|
||||
$breadcrumb->addLink(Link::createFromRoute($this->t('Results'), "entity.$entity_type.webform.results_submissions", [$entity_type => $entity_id]));
|
||||
}
|
||||
elseif ($webform_submission->access('view_own')) {
|
||||
$breadcrumb->addLink(Link::createFromRoute($this->t('Results'), "entity.$entity_type.webform.user.submissions", [$entity_type => $entity_id]));
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
$breadcrumb = new Breadcrumb();
|
||||
$breadcrumb->addLink(Link::createFromRoute($this->t('Home'), '<front>'));
|
||||
$breadcrumb->addLink(Link::createFromRoute($this->t('Administration'), 'system.admin'));
|
||||
$breadcrumb->addLink(Link::createFromRoute($this->t('Structure'), 'system.admin_structure'));
|
||||
$breadcrumb->addLink(Link::createFromRoute($this->t('Webforms'), 'entity.webform.collection'));
|
||||
switch ($this->type) {
|
||||
case 'webform_test':
|
||||
$breadcrumb->addLink(Link::createFromRoute($this->t('Testing'), 'webform_test.index'));
|
||||
break;
|
||||
|
||||
case 'webform_template':
|
||||
$breadcrumb->addLink(Link::createFromRoute($this->t('Templates'), 'entity.webform.templates'));
|
||||
break;
|
||||
|
||||
case 'webform_element':
|
||||
/** @var \Drupal\webform\WebformInterface $webform */
|
||||
$webform = $route_match->getParameter('webform');
|
||||
$breadcrumb->addLink(Link::createFromRoute($webform->label(), 'entity.webform.canonical', ['webform' => $webform->id()]));
|
||||
$breadcrumb->addLink(Link::createFromRoute($this->t('Elements'), 'entity.webform.edit_form', ['webform' => $webform->id()]));
|
||||
break;
|
||||
|
||||
case 'webform_handler':
|
||||
/** @var \Drupal\webform\WebformInterface $webform */
|
||||
$webform = $route_match->getParameter('webform');
|
||||
$breadcrumb->addLink(Link::createFromRoute($webform->label(), 'entity.webform.canonical', ['webform' => $webform->id()]));
|
||||
$breadcrumb->addLink(Link::createFromRoute($this->t('Emails / Handlers'), 'entity.webform.handlers_form', ['webform' => $webform->id()]));
|
||||
break;
|
||||
|
||||
case 'webform_submission':
|
||||
/** @var \Drupal\webform\WebformSubmissionInterface $webform_submission */
|
||||
$webform_submission = $route_match->getParameter('webform_submission');
|
||||
$webform = $webform_submission->getWebform();
|
||||
$breadcrumb->addLink(Link::createFromRoute($webform->label(), 'entity.webform.canonical', ['webform' => $webform->id()]));
|
||||
$breadcrumb->addLink(Link::createFromRoute($this->t('Results'), 'entity.webform.results_submissions', ['webform' => $webform->id()]));
|
||||
break;
|
||||
|
||||
case 'webform_user_submissions':
|
||||
/** @var \Drupal\webform\WebformInterface $webform */
|
||||
$webform = $route_match->getParameter('webform');
|
||||
$breadcrumb = new Breadcrumb();
|
||||
$breadcrumb->addLink(Link::createFromRoute($webform->label(), 'entity.webform.canonical', ['webform' => $webform->id()]));
|
||||
break;
|
||||
|
||||
case 'webform_user_submission':
|
||||
/** @var \Drupal\webform\WebformSubmissionInterface $webform_submission */
|
||||
$webform_submission = $route_match->getParameter('webform_submission');
|
||||
$webform = $webform_submission->getWebform();
|
||||
$breadcrumb = new Breadcrumb();
|
||||
$breadcrumb->addLink(Link::createFromRoute($webform->label(), 'entity.webform.canonical', ['webform' => $webform->id()]));
|
||||
$breadcrumb->addLink(Link::createFromRoute($this->t('Submissions'), 'entity.webform.user.submissions', ['webform' => $webform->id()]));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// This breadcrumb builder is based on a route parameter, and hence it
|
||||
// depends on the 'route' cache context.
|
||||
$breadcrumb->addCacheContexts(['route']);
|
||||
|
||||
return $breadcrumb;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,67 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\webform\ContextProvider;
|
||||
|
||||
use Drupal\Core\Cache\CacheableMetadata;
|
||||
use Drupal\Core\Plugin\Context\Context;
|
||||
use Drupal\Core\Plugin\Context\ContextDefinition;
|
||||
use Drupal\Core\Plugin\Context\ContextProviderInterface;
|
||||
use Drupal\Core\Routing\RouteMatchInterface;
|
||||
use Drupal\Core\StringTranslation\StringTranslationTrait;
|
||||
|
||||
/**
|
||||
* Sets the current webform as a context on webform routes.
|
||||
*/
|
||||
class WebformRouteContext implements ContextProviderInterface {
|
||||
|
||||
use StringTranslationTrait;
|
||||
|
||||
/**
|
||||
* The route match object.
|
||||
*
|
||||
* @var \Drupal\Core\Routing\RouteMatchInterface
|
||||
*/
|
||||
protected $routeMatch;
|
||||
|
||||
/**
|
||||
* Constructs a new WebformRouteContext.
|
||||
*
|
||||
* @param \Drupal\Core\Routing\RouteMatchInterface $route_match
|
||||
* The route match object.
|
||||
*/
|
||||
public function __construct(RouteMatchInterface $route_match) {
|
||||
$this->routeMatch = $route_match;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getRuntimeContexts(array $unqualified_context_ids) {
|
||||
$result = [];
|
||||
$context_definition = new ContextDefinition('entity:webform', NULL, FALSE);
|
||||
$value = NULL;
|
||||
if (($route_object = $this->routeMatch->getRouteObject()) && ($route_contexts = $route_object->getOption('parameters')) && isset($route_contexts['webform'])) {
|
||||
if ($webform = $this->routeMatch->getParameter('webform')) {
|
||||
$value = $webform;
|
||||
}
|
||||
}
|
||||
|
||||
$cacheability = new CacheableMetadata();
|
||||
$cacheability->setCacheContexts(['route']);
|
||||
|
||||
$context = new Context($context_definition, $value);
|
||||
$context->addCacheableDependency($cacheability);
|
||||
$result['webform'] = $context;
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getAvailableContexts() {
|
||||
$context = new Context(new ContextDefinition('entity:webform', $this->t('Webform from URL')));
|
||||
return ['webform' => $context];
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,67 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\webform\ContextProvider;
|
||||
|
||||
use Drupal\Core\Cache\CacheableMetadata;
|
||||
use Drupal\Core\Plugin\Context\Context;
|
||||
use Drupal\Core\Plugin\Context\ContextDefinition;
|
||||
use Drupal\Core\Plugin\Context\ContextProviderInterface;
|
||||
use Drupal\Core\Routing\RouteMatchInterface;
|
||||
use Drupal\Core\StringTranslation\StringTranslationTrait;
|
||||
|
||||
/**
|
||||
* Sets the current webform submission as a context on webform submission routes.
|
||||
*/
|
||||
class WebformSubmissionRouteContext implements ContextProviderInterface {
|
||||
|
||||
use StringTranslationTrait;
|
||||
|
||||
/**
|
||||
* The route match object.
|
||||
*
|
||||
* @var \Drupal\Core\Routing\RouteMatchInterface
|
||||
*/
|
||||
protected $routeMatch;
|
||||
|
||||
/**
|
||||
* Constructs a new WebformSubmissionRouteContext.
|
||||
*
|
||||
* @param \Drupal\Core\Routing\RouteMatchInterface $route_match
|
||||
* The route match object.
|
||||
*/
|
||||
public function __construct(RouteMatchInterface $route_match) {
|
||||
$this->routeMatch = $route_match;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getRuntimeContexts(array $unqualified_context_ids) {
|
||||
$result = [];
|
||||
$context_definition = new ContextDefinition('entity:webform_submission', NULL, FALSE);
|
||||
$value = NULL;
|
||||
if (($route_object = $this->routeMatch->getRouteObject()) && ($route_contexts = $route_object->getOption('parameters')) && isset($route_contexts['webform_submission'])) {
|
||||
if ($webform_submission = $this->routeMatch->getParameter('webform_submission')) {
|
||||
$value = $webform_submission;
|
||||
}
|
||||
}
|
||||
|
||||
$cacheability = new CacheableMetadata();
|
||||
$cacheability->setCacheContexts(['route']);
|
||||
|
||||
$context = new Context($context_definition, $value);
|
||||
$context->addCacheableDependency($cacheability);
|
||||
$result['webform_submission'] = $context;
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getAvailableContexts() {
|
||||
$context = new Context(new ContextDefinition('entity:webform_submission', $this->t('Webform submission from URL')));
|
||||
return ['webform_submission' => $context];
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,76 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\webform\Controller;
|
||||
|
||||
use Drupal\Core\Controller\ControllerBase;
|
||||
use Drupal\Core\DependencyInjection\ContainerInjectionInterface;
|
||||
use Drupal\webform\WebformAddonsManagerInterface;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
|
||||
/**
|
||||
* Provides route responses for webform add-on.
|
||||
*/
|
||||
class WebformAddonsController extends ControllerBase implements ContainerInjectionInterface {
|
||||
|
||||
/**
|
||||
* The add-ons manager.
|
||||
*
|
||||
* @var \Drupal\webform\WebformAddonsManagerInterface
|
||||
*/
|
||||
protected $addons;
|
||||
|
||||
/**
|
||||
* Constructs a WebformAddonsController object.
|
||||
*
|
||||
* @param \Drupal\webform\WebformAddonsManagerInterface $addons
|
||||
* The add-ons manager.
|
||||
*/
|
||||
public function __construct(WebformAddonsManagerInterface $addons) {
|
||||
$this->addons = $addons;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function create(ContainerInterface $container) {
|
||||
return new static(
|
||||
$container->get('webform.addons_manager')
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the Webform extend page.
|
||||
*
|
||||
* @return array
|
||||
* The webform submission webform.
|
||||
*/
|
||||
public function index() {
|
||||
$build = [
|
||||
'#type' => 'container',
|
||||
'#attributes' => [
|
||||
'class' => ['webform-addons', 'js-webform-details-toggle', 'webform-details-toggle'],
|
||||
],
|
||||
];
|
||||
$build['#attached']['library'][] = 'webform/webform.admin';
|
||||
$build['#attached']['library'][] = 'webform/webform.element.details.toggle';
|
||||
|
||||
$categories = $this->addons->getCategories();
|
||||
foreach ($categories as $category_name => $category) {
|
||||
$build[$category_name] = [
|
||||
'#type' => 'details',
|
||||
'#title' => $category['title'],
|
||||
'#open' => TRUE,
|
||||
];
|
||||
$projects = $this->addons->getProjects($category_name);
|
||||
foreach ($projects as &$project) {
|
||||
$project['description'] .= ' ' . '<br/><small>' . $project['url']->toString() . '</small>';
|
||||
}
|
||||
$build[$category_name]['content'] = [
|
||||
'#theme' => 'admin_block_content',
|
||||
'#content' => $projects,
|
||||
];
|
||||
}
|
||||
return $build;
|
||||
}
|
||||
|
||||
}
|
||||
234
web/modules/contrib/webform/src/Controller/WebformController.php
Normal file
234
web/modules/contrib/webform/src/Controller/WebformController.php
Normal file
|
|
@ -0,0 +1,234 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\webform\Controller;
|
||||
|
||||
use Drupal\Component\Render\FormattableMarkup;
|
||||
use Drupal\Core\Controller\ControllerBase;
|
||||
use Drupal\Core\DependencyInjection\ContainerInjectionInterface;
|
||||
use Drupal\Core\Render\RendererInterface;
|
||||
use Drupal\webform\WebformInterface;
|
||||
use Drupal\webform\WebformRequestInterface;
|
||||
use Drupal\webform\WebformTokenManagerInterface;
|
||||
use Symfony\Component\HttpFoundation\JsonResponse;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
|
||||
/**
|
||||
* Provides route responses for webform.
|
||||
*/
|
||||
class WebformController extends ControllerBase implements ContainerInjectionInterface {
|
||||
|
||||
/**
|
||||
* The renderer service.
|
||||
*
|
||||
* @var \Drupal\Core\Render\RendererInterface
|
||||
*/
|
||||
protected $renderer;
|
||||
|
||||
/**
|
||||
* Webform request handler.
|
||||
*
|
||||
* @var \Drupal\webform\WebformRequestInterface
|
||||
*/
|
||||
protected $requestHandler;
|
||||
|
||||
/**
|
||||
* The token manager.
|
||||
*
|
||||
* @var \Drupal\webform\WebformTranslationManagerInterface
|
||||
*/
|
||||
protected $tokenManager;
|
||||
|
||||
/**
|
||||
* Constructs a WebformController object.
|
||||
*
|
||||
* @param \Drupal\Core\Render\RendererInterface $renderer
|
||||
* The renderer service.
|
||||
* @param \Drupal\webform\WebformRequestInterface $request_handler
|
||||
* The webform request handler.
|
||||
* @param \Drupal\webform\WebformTokenManagerInterface $token_manager
|
||||
* The token manager.
|
||||
*/
|
||||
public function __construct(RendererInterface $renderer, WebformRequestInterface $request_handler, WebformTokenManagerInterface $token_manager) {
|
||||
$this->renderer = $renderer;
|
||||
$this->requestHandler = $request_handler;
|
||||
$this->tokenManager = $token_manager;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function create(ContainerInterface $container) {
|
||||
return new static(
|
||||
$container->get('renderer'),
|
||||
$container->get('webform.request'),
|
||||
$container->get('webform.token_manager')
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a webform to add a new submission to a webform.
|
||||
*
|
||||
* @param \Symfony\Component\HttpFoundation\Request $request
|
||||
* The current request.
|
||||
* @param \Drupal\webform\WebformInterface $webform
|
||||
* The webform this submission will be added to.
|
||||
*
|
||||
* @return array
|
||||
* The webform submission webform.
|
||||
*/
|
||||
public function addForm(Request $request, WebformInterface $webform) {
|
||||
return $webform->getSubmissionForm();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a webform's CSS.
|
||||
*
|
||||
* @param \Symfony\Component\HttpFoundation\Request $request
|
||||
* The current request.
|
||||
* @param \Drupal\webform\WebformInterface $webform
|
||||
* The webform.
|
||||
*
|
||||
* @return \Symfony\Component\HttpFoundation\Response
|
||||
* The response object.
|
||||
*/
|
||||
public function css(Request $request, WebformInterface $webform) {
|
||||
$assets = $webform->getAssets();
|
||||
return new Response($assets['css'], 200, ['Content-Type' => 'text/css']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a webform's JavaScript.
|
||||
*
|
||||
* @param \Symfony\Component\HttpFoundation\Request $request
|
||||
* The current request.
|
||||
* @param \Drupal\webform\WebformInterface $webform
|
||||
* The webform.
|
||||
*
|
||||
* @return \Symfony\Component\HttpFoundation\Response
|
||||
* The response object.
|
||||
*/
|
||||
public function javascript(Request $request, WebformInterface $webform) {
|
||||
$assets = $webform->getAssets();
|
||||
return new Response($assets['javascript'], 200, ['Content-Type' => 'text/javascript']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a webform confirmation page.
|
||||
*
|
||||
* @param \Symfony\Component\HttpFoundation\Request $request
|
||||
* The current request.
|
||||
* @param \Drupal\webform\WebformInterface|null $webform
|
||||
* A webform.
|
||||
*
|
||||
* @return array
|
||||
* A render array representing a webform confirmation page
|
||||
*/
|
||||
public function confirmation(Request $request, WebformInterface $webform = NULL) {
|
||||
/** @var \Drupal\Core\Entity\EntityInterface $source_entity */
|
||||
if (!$webform) {
|
||||
list($webform, $source_entity) = $this->requestHandler->getWebformEntities();
|
||||
}
|
||||
else {
|
||||
$source_entity = $this->requestHandler->getCurrentSourceEntity('webform');
|
||||
}
|
||||
|
||||
/** @var \Drupal\webform\WebformSubmissionInterface $webform_submission */
|
||||
$webform_submission = NULL;
|
||||
|
||||
if ($token = $request->get('token')) {
|
||||
/** @var \Drupal\webform\WebformSubmissionStorageInterface $webform_submission_storage */
|
||||
$webform_submission_storage = $this->entityTypeManager()->getStorage('webform_submission');
|
||||
if ($entities = $webform_submission_storage->loadByProperties(['token' => $token])) {
|
||||
$webform_submission = reset($entities);
|
||||
}
|
||||
}
|
||||
|
||||
// Get title.
|
||||
$title = $webform->getSetting('confirmation_title') ?: (($source_entity) ? $source_entity->label() : $webform->label());
|
||||
|
||||
// Replace tokens in title.
|
||||
$title = $this->tokenManager->replace($title, $webform_submission ?: $webform);
|
||||
|
||||
$build = [
|
||||
'#title' => $title,
|
||||
'#theme' => 'webform_confirmation',
|
||||
'#webform' => $webform,
|
||||
'#source_entity' => $source_entity,
|
||||
'#webform_submission' => $webform_submission,
|
||||
];
|
||||
|
||||
$this->renderer->addCacheableDependency($build, $webform);
|
||||
return $build;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a webform filter webform autocomplete matches.
|
||||
*
|
||||
* @param \Symfony\Component\HttpFoundation\Request $request
|
||||
* The current request.
|
||||
* @param bool $templates
|
||||
* If TRUE, limit autocomplete matches to webform templates.
|
||||
*
|
||||
* @return \Symfony\Component\HttpFoundation\JsonResponse
|
||||
* The JSON response.
|
||||
*/
|
||||
public function autocomplete(Request $request, $templates = FALSE) {
|
||||
$q = $request->query->get('q');
|
||||
|
||||
$webform_storage = $this->entityTypeManager()->getStorage('webform');
|
||||
|
||||
$query = $webform_storage->getQuery()
|
||||
->condition('title', $q, 'CONTAINS')
|
||||
->range(0, 10)
|
||||
->sort('title');
|
||||
|
||||
// Limit query to templates.
|
||||
if ($templates) {
|
||||
$query->condition('template', TRUE);
|
||||
}
|
||||
elseif ($this->moduleHandler()->moduleExists('webform_templates')) {
|
||||
// Filter out templates if the webform_template.module is enabled.
|
||||
$query->condition('template', FALSE);
|
||||
}
|
||||
|
||||
$entity_ids = $query->execute();
|
||||
|
||||
if (empty($entity_ids)) {
|
||||
return new JsonResponse([]);
|
||||
}
|
||||
$webforms = $webform_storage->loadMultiple($entity_ids);
|
||||
|
||||
$matches = [];
|
||||
foreach ($webforms as $webform) {
|
||||
if ($webform->access('view')) {
|
||||
$value = new FormattableMarkup('@label (@id)', ['@label' => $webform->label(), '@id' => $webform->id()]);
|
||||
$matches[] = ['value' => $value, 'label' => $value];
|
||||
}
|
||||
}
|
||||
|
||||
return new JsonResponse($matches);
|
||||
}
|
||||
|
||||
/**
|
||||
* Route title callback.
|
||||
*
|
||||
* @param \Drupal\webform\WebformInterface|null $webform
|
||||
* A webform.
|
||||
*
|
||||
* @return string
|
||||
* The webform label as a render array.
|
||||
*/
|
||||
public function title(WebformInterface $webform = NULL) {
|
||||
/** @var \Drupal\Core\Entity\EntityInterface $source_entity */
|
||||
if (!$webform) {
|
||||
list($webform, $source_entity) = $this->requestHandler->getWebformEntities();
|
||||
}
|
||||
else {
|
||||
$source_entity = $this->requestHandler->getCurrentSourceEntity('webform');
|
||||
}
|
||||
return ($source_entity) ? $source_entity->label() : $webform->label();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,224 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\webform\Controller;
|
||||
|
||||
use Drupal\Component\Utility\Unicode;
|
||||
use Drupal\Core\Ajax\AjaxResponse;
|
||||
use Drupal\Core\Controller\ControllerBase;
|
||||
use Drupal\Core\Database\Database;
|
||||
use Drupal\webform\Element\WebformMessage;
|
||||
use Drupal\webform\Entity\WebformOptions;
|
||||
use Drupal\webform\WebformInterface;
|
||||
use Symfony\Component\HttpFoundation\JsonResponse;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
|
||||
/**
|
||||
* Provides route responses for webform element.
|
||||
*/
|
||||
class WebformElementController extends ControllerBase {
|
||||
|
||||
/**
|
||||
* Returns response for message close using user or state storage.
|
||||
*
|
||||
* @param string $storage
|
||||
* Mechanism that the message state should be stored in, user or state.
|
||||
* @param string $id
|
||||
* The unique id of the message.
|
||||
*
|
||||
* @return \Drupal\Core\Ajax\AjaxResponse
|
||||
* An empty AJAX response.
|
||||
*
|
||||
* @throws \Exception
|
||||
* Throws exception is storage is not set to 'user' or 'state'.
|
||||
*
|
||||
* @see \Drupal\webform\Element\WebformMessage::setClosed
|
||||
*/
|
||||
public function close($storage, $id) {
|
||||
if (!in_array($storage, ['user', 'state'])) {
|
||||
throw new \Exception('Undefined storage mechanism for Webform close message.');
|
||||
}
|
||||
WebformMessage::setClosed($storage, $id);
|
||||
return new AjaxResponse();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns response for the element autocomplete route.
|
||||
*
|
||||
* @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) {
|
||||
// Get autocomplete query.
|
||||
$q = $request->query->get('q') ?: '';
|
||||
if ($q == '') {
|
||||
return new JsonResponse([]);
|
||||
}
|
||||
|
||||
// Get the initialized webform element.
|
||||
$element = $webform->getElement($key);
|
||||
if (!$element) {
|
||||
return new JsonResponse([]);
|
||||
}
|
||||
|
||||
// Set default autocomplete properties.
|
||||
$element += [
|
||||
'#autocomplete_existing' => FALSE,
|
||||
'#autocomplete_items' => [],
|
||||
'#autocomplete_match' => 3,
|
||||
'#autocomplete_limit' => 10,
|
||||
'#autocomplete_match_operator' => 'CONTAINS',
|
||||
];
|
||||
|
||||
// Check minimum number of characters.
|
||||
if (Unicode::strlen($q) < (int) $element['#autocomplete_match']) {
|
||||
return new JsonResponse([]);
|
||||
}
|
||||
|
||||
$matches = [];
|
||||
|
||||
// Get existing matches.
|
||||
if (!empty($element['#autocomplete_existing'])) {
|
||||
$matches += $this->getMatchesFromExistingValues($q, $webform->id(), $key, $element['#autocomplete_match_operator'], $element['#autocomplete_limit']);
|
||||
}
|
||||
|
||||
// Get items (aka options) matches.
|
||||
if (!empty($element['#autocomplete_items'])) {
|
||||
$element['#options'] = $element['#autocomplete_items'];
|
||||
$options = WebformOptions::getElementOptions($element);
|
||||
$matches += $this->getMatchesFromOptions($q, $options, $element['#autocomplete_match_operator'], $element['#autocomplete_limit']);
|
||||
}
|
||||
|
||||
// Sort matches by label and enforce the limit.
|
||||
if ($matches) {
|
||||
uasort($matches, function (array $a, array $b) {
|
||||
return $a['label'] > $b['label'];
|
||||
});
|
||||
$matches = array_values($matches);
|
||||
$matches = array_slice($matches, 0, $element['#autocomplete_limit']);
|
||||
}
|
||||
|
||||
return new JsonResponse($matches);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get matches from existing submission values.
|
||||
*
|
||||
* @param string $q
|
||||
* String to filter option's label by.
|
||||
* @param string $webform_id
|
||||
* The webform id.
|
||||
* @param string $key
|
||||
* The element's key.
|
||||
* @param string $operator
|
||||
* Match operator either CONTAINS or STARTS_WITH.
|
||||
* @param int $limit
|
||||
* Limit number of matches.
|
||||
*
|
||||
* @return array
|
||||
* An array of matches.
|
||||
*/
|
||||
protected function getMatchesFromExistingValues($q, $webform_id, $key, $operator = 'CONTAINS', $limit = 10) {
|
||||
// Query webform submission for existing values.
|
||||
$query = Database::getConnection()->select('webform_submission_data')
|
||||
->fields('webform_submission_data', ['value'])
|
||||
->condition('webform_id', $webform_id)
|
||||
->condition('name', $key)
|
||||
->condition('value', ($operator == 'START_WITH') ? "$q%" : "%$q%", 'LIKE')
|
||||
->orderBy('value');
|
||||
if ($limit) {
|
||||
$query->range(0, $limit);
|
||||
}
|
||||
|
||||
// Convert query results values to matches array.
|
||||
$values = $query->execute()->fetchCol();
|
||||
$matches = [];
|
||||
foreach ($values as $value) {
|
||||
$matches[$value] = ['value' => $value, 'label' => $value];
|
||||
}
|
||||
return $matches;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get matches from options.
|
||||
*
|
||||
* @param string $q
|
||||
* String to filter option's label by.
|
||||
* @param array $options
|
||||
* An associative array of webform options.
|
||||
* @param string $operator
|
||||
* Match operator either CONTAINS or STARTS_WITH.
|
||||
* @param int $limit
|
||||
* Limit number of matches.
|
||||
*
|
||||
* @return array
|
||||
* An array of matches sorted by label.
|
||||
*/
|
||||
protected function getMatchesFromOptions($q, array $options, $operator = 'CONTAINS', $limit = 10) {
|
||||
// Make sure options are populated.
|
||||
if (empty($options)) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$matches = [];
|
||||
|
||||
// Filter and convert options to autocomplete matches.
|
||||
$this->getMatchesFromOptionsRecursive($q, $options, $matches, $operator);
|
||||
|
||||
// Sort matches.
|
||||
ksort($matches);
|
||||
|
||||
// Apply match limit.
|
||||
if ($limit) {
|
||||
$matches = array_slice($matches, 0, $limit);
|
||||
}
|
||||
|
||||
return array_values($matches);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get matches from options recursive.
|
||||
*
|
||||
* @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.
|
||||
* @param string $operator
|
||||
* Match operator either CONTAINS or STARTS_WITH.
|
||||
*/
|
||||
protected function getMatchesFromOptionsRecursive($q, array $options, array &$matches, $operator = 'CONTAINS') {
|
||||
foreach ($options as $value => $label) {
|
||||
if (is_array($label)) {
|
||||
$this->getMatchesFromOptionsRecursive($q, $label, $matches, $operator);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Cast TranslatableMarkup to string.
|
||||
$label = (string) $label;
|
||||
|
||||
if ($operator == 'STARTS_WITH' && stripos($label, $q) === 0) {
|
||||
$matches[$label] = [
|
||||
'value' => $label,
|
||||
'label' => $label,
|
||||
];
|
||||
}
|
||||
// Default to CONTAINS even when operator is empty.
|
||||
elseif (stripos($label, $q) !== FALSE) {
|
||||
$matches[$label] = [
|
||||
'value' => $label,
|
||||
'label' => $label,
|
||||
];
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,96 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\webform\Controller;
|
||||
|
||||
use Drupal\Core\Controller\ControllerBase;
|
||||
use Drupal\Core\DependencyInjection\ContainerInjectionInterface;
|
||||
use Drupal\webform\WebformHelpManagerInterface;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
|
||||
/**
|
||||
* Provides route responses for webform help.
|
||||
*/
|
||||
class WebformHelpController extends ControllerBase implements ContainerInjectionInterface {
|
||||
|
||||
/**
|
||||
* The help manager.
|
||||
*
|
||||
* @var \Drupal\Component\Plugin\PluginManagerInterface
|
||||
*/
|
||||
protected $helpManager;
|
||||
|
||||
/**
|
||||
* Constructs a WebformHelpController object.
|
||||
*
|
||||
* @param \Drupal\webform\WebformHelpManagerInterface $help_manager
|
||||
* The help manager.
|
||||
*/
|
||||
public function __construct(WebformHelpManagerInterface $help_manager) {
|
||||
$this->helpManager = $help_manager;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function create(ContainerInterface $container) {
|
||||
return new static(
|
||||
$container->get('webform.help_manager')
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns dedicated help video page.
|
||||
*
|
||||
* @param \Symfony\Component\HttpFoundation\Request $request
|
||||
* The current request.
|
||||
* @param string $id
|
||||
* The video id.
|
||||
*
|
||||
* @return array
|
||||
* A renderable array containing a help video player page.
|
||||
*/
|
||||
public function index(Request $request, $id) {
|
||||
$id = str_replace('-', '_', $id);
|
||||
$video = $this->helpManager->getVideo($id);
|
||||
if (!$video) {
|
||||
throw new NotFoundHttpException();
|
||||
}
|
||||
|
||||
$build = [];
|
||||
if (is_array($video['content'])) {
|
||||
$build['content'] = $video['content'];
|
||||
}
|
||||
else {
|
||||
$build['content'] = [
|
||||
'#markup' => $video['content'],
|
||||
];
|
||||
}
|
||||
if ($video['youtube_id']) {
|
||||
$build['video'] = [
|
||||
'#theme' => 'webform_help_video_youtube',
|
||||
'#youtube_id' => $video['youtube_id'],
|
||||
];
|
||||
}
|
||||
return $build;
|
||||
}
|
||||
|
||||
/**
|
||||
* Route title callback.
|
||||
*
|
||||
* @param \Symfony\Component\HttpFoundation\Request $request
|
||||
* The current request.
|
||||
* @param string $id
|
||||
* The id of the dedicated help section.
|
||||
*
|
||||
* @return string
|
||||
* The dedicated help section's title.
|
||||
*/
|
||||
public function title(Request $request, $id) {
|
||||
$id = str_replace('-', '_', $id);
|
||||
$video = $this->helpManager->getVideo($id);
|
||||
return (isset($video)) ? $video['title'] : $this->t('Watch video');
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,95 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\webform\Controller;
|
||||
|
||||
use Drupal\Core\Controller\ControllerBase;
|
||||
use Drupal\webform\Entity\WebformOptions;
|
||||
use Drupal\webform\WebformInterface;
|
||||
use Drupal\webform\WebformOptionsInterface;
|
||||
use Symfony\Component\HttpFoundation\JsonResponse;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
|
||||
/**
|
||||
* Provides route responses for webform options.
|
||||
*/
|
||||
class WebformOptionsController extends ControllerBase {
|
||||
|
||||
/**
|
||||
* Returns response for the element 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) {
|
||||
$q = $request->query->get('q');
|
||||
|
||||
// Make sure the current user can access this webform.
|
||||
if (!$webform->access('view')) {
|
||||
return new JsonResponse([]);
|
||||
}
|
||||
|
||||
// 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);
|
||||
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,
|
||||
];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Route title callback.
|
||||
*
|
||||
* @param \Drupal\webform\WebformOptionsInterface $webform_options
|
||||
* The webform options.
|
||||
*
|
||||
* @return string
|
||||
* The webform options label as a render array.
|
||||
*/
|
||||
public function title(WebformOptionsInterface $webform_options) {
|
||||
return $webform_options->label();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,315 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\webform\Controller;
|
||||
|
||||
use Drupal\Component\Render\FormattableMarkup;
|
||||
use Drupal\Core\DependencyInjection\ContainerInjectionInterface;
|
||||
use Drupal\Core\Extension\ModuleHandlerInterface;
|
||||
use Drupal\Core\Controller\ControllerBase;
|
||||
use Drupal\Core\Render\ElementInfoManagerInterface;
|
||||
use Drupal\Core\Url;
|
||||
use Drupal\webform\Utility\WebformReflectionHelper;
|
||||
use Drupal\webform\WebformElementManagerInterface;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
|
||||
/**
|
||||
* Controller for all webform elements.
|
||||
*/
|
||||
class WebformPluginElementController extends ControllerBase implements ContainerInjectionInterface {
|
||||
|
||||
/**
|
||||
* The module handler.
|
||||
*
|
||||
* @var \Drupal\Core\Extension\ModuleHandlerInterface
|
||||
*/
|
||||
protected $moduleHandler;
|
||||
|
||||
/**
|
||||
* A element info manager.
|
||||
*
|
||||
* @var \Drupal\Core\Render\ElementInfoManagerInterface
|
||||
*/
|
||||
protected $elementInfo;
|
||||
|
||||
/**
|
||||
* A webform element plugin manager.
|
||||
*
|
||||
* @var \Drupal\webform\WebformElementManagerInterface
|
||||
*/
|
||||
protected $elementManager;
|
||||
|
||||
/**
|
||||
* Constructs a WebformPluginElementController object.
|
||||
*
|
||||
* @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler
|
||||
* The module handler.
|
||||
* @param \Drupal\Core\Render\ElementInfoManagerInterface $element_info
|
||||
* A element info plugin manager.
|
||||
* @param \Drupal\webform\WebformElementManagerInterface $element_manager
|
||||
* A webform element plugin manager.
|
||||
*/
|
||||
public function __construct(ModuleHandlerInterface $module_handler, ElementInfoManagerInterface $element_info, WebformElementManagerInterface $element_manager) {
|
||||
$this->moduleHandler = $module_handler;
|
||||
$this->elementInfo = $element_info;
|
||||
$this->elementManager = $element_manager;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function create(ContainerInterface $container) {
|
||||
return new static(
|
||||
$container->get('module_handler'),
|
||||
$container->get('plugin.manager.element_info'),
|
||||
$container->get('plugin.manager.webform.element')
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function index() {
|
||||
$webform_form_element_rows = [];
|
||||
$element_rows = [];
|
||||
|
||||
$default_properties = [
|
||||
// Element settings.
|
||||
'title',
|
||||
'description',
|
||||
'default_value',
|
||||
// Form display.
|
||||
'title_display',
|
||||
'description_display',
|
||||
'field_prefix',
|
||||
'field_suffix',
|
||||
// Form validation.
|
||||
'required',
|
||||
'required_error',
|
||||
'unique',
|
||||
// Submission display.
|
||||
'format',
|
||||
// Attributes.
|
||||
'wrapper_attributes',
|
||||
'attributes',
|
||||
// Administration.
|
||||
'admin_title',
|
||||
'private',
|
||||
// Flexbox.
|
||||
'flex',
|
||||
// Conditional logic.
|
||||
'states',
|
||||
// Element access.
|
||||
'access_create_roles',
|
||||
'access_create_users',
|
||||
'access_update_roles',
|
||||
'access_update_users',
|
||||
'access_view_roles',
|
||||
'access_view_users',
|
||||
];;
|
||||
$default_properties = array_combine($default_properties, $default_properties);
|
||||
|
||||
// Test element is only enabled if the Webform Devel and UI module are
|
||||
// enabled.
|
||||
$test_element_enabled = ($this->moduleHandler->moduleExists('webform_devel') && $this->moduleHandler->moduleExists('webform_ui')) ? TRUE : FALSE;
|
||||
|
||||
// Define a default element used to get default properties.
|
||||
$element = ['#type' => 'element'];
|
||||
|
||||
$element_plugin_definitions = $this->elementInfo->getDefinitions();
|
||||
foreach ($element_plugin_definitions as $element_plugin_id => $element_plugin_definition) {
|
||||
if ($this->elementManager->hasDefinition($element_plugin_id)) {
|
||||
|
||||
/** @var \Drupal\webform\WebformElementInterface $webform_element */
|
||||
$webform_element = $this->elementManager->createInstance($element_plugin_id);
|
||||
$webform_element_plugin_definition = $this->elementManager->getDefinition($element_plugin_id);
|
||||
$webform_element_info = $webform_element->getInfo();
|
||||
|
||||
$parent_classes = WebformReflectionHelper::getParentClasses($webform_element, 'WebformElementBase');
|
||||
|
||||
$default_format = $webform_element->getItemDefaultFormat();
|
||||
$format_names = array_keys($webform_element->getItemFormats());
|
||||
$formats = array_combine($format_names, $format_names);
|
||||
if (isset($formats[$default_format])) {
|
||||
$formats[$default_format] = '<b>' . $formats[$default_format] . '</b>';
|
||||
}
|
||||
|
||||
$related_types = $webform_element->getRelatedTypes($element);
|
||||
|
||||
$webform_info_definitions = [
|
||||
'input' => $webform_element->isInput($element),
|
||||
'container' => $webform_element->isContainer($element),
|
||||
'root' => $webform_element->isRoot(),
|
||||
'hidden' => $webform_element->isHidden(),
|
||||
'multiple' => $webform_element->supportsMultipleValues(),
|
||||
'multiline' => $webform_element->isMultiline($element),
|
||||
'states_wrapper' => $webform_element_plugin_definition['states_wrapper'],
|
||||
];
|
||||
$webform_info = [];
|
||||
foreach ($webform_info_definitions as $key => $value) {
|
||||
$webform_info[] = '<b>' . $key . '</b>: ' . ($value ? $this->t('Yes') : $this->t('No'));
|
||||
}
|
||||
|
||||
$element_info_definitions = [
|
||||
'input' => (empty($webform_element_info['#input'])) ? $this->t('No') : $this->t('Yes'),
|
||||
'theme' => (isset($webform_element_info['#theme'])) ? $webform_element_info['#theme'] : 'N/A',
|
||||
'theme_wrappers' => (isset($webform_element_info['#theme_wrappers'])) ? implode('; ', $webform_element_info['#theme_wrappers']) : 'N/A',
|
||||
];
|
||||
$element_info = [];
|
||||
foreach ($element_info_definitions as $key => $value) {
|
||||
$element_info[] = '<b>' . $key . '</b>: ' . $value;
|
||||
}
|
||||
|
||||
$properties = [];
|
||||
$element_default_properties = array_keys($webform_element->getDefaultProperties());
|
||||
foreach ($element_default_properties as $key => $value) {
|
||||
if (!isset($default_properties[$value])) {
|
||||
$properties[$key] = '<b>#' . $value . '</b>';
|
||||
unset($element_default_properties[$key]);
|
||||
}
|
||||
else {
|
||||
$element_default_properties[$key] = '#' . $value;
|
||||
}
|
||||
}
|
||||
$properties += $element_default_properties;
|
||||
if (count($properties) >= 20) {
|
||||
$properties = array_slice($properties, 0, 20) + ['...' => '...'];
|
||||
}
|
||||
|
||||
$operations = [];
|
||||
if ($test_element_enabled) {
|
||||
$operations['test'] = [
|
||||
'title' => $this->t('Test'),
|
||||
'url' => new Url('webform.element_plugins.test', ['type' => $element_plugin_id]),
|
||||
];
|
||||
}
|
||||
if ($api_url = $webform_element->getPluginApiUrl()) {
|
||||
$operations['documentation'] = [
|
||||
'title' => $this->t('API Docs'),
|
||||
'url' => $api_url,
|
||||
];
|
||||
}
|
||||
$webform_form_element_rows[$element_plugin_id] = [
|
||||
'data' => [
|
||||
new FormattableMarkup('<div class="webform-form-filter-text-source">@id</div>', ['@id' => $element_plugin_id]),
|
||||
new FormattableMarkup('<strong>@label</strong><br/>@description', ['@label' => $webform_element->getPluginLabel(), '@description' => $webform_element->getPluginDescription()]),
|
||||
['data' => ['#markup' => implode('<br/> → ', $parent_classes)], 'nowrap' => 'nowrap'],
|
||||
['data' => ['#markup' => implode('<br/>', $webform_info)], 'nowrap' => 'nowrap'],
|
||||
['data' => ['#markup' => implode('<br/>', $element_info)], 'nowrap' => 'nowrap'],
|
||||
['data' => ['#markup' => implode('<br/>', $properties)]],
|
||||
$formats ? ['data' => ['#markup' => '• ' . implode('<br/>• ', $formats)], 'nowrap' => 'nowrap'] : '',
|
||||
$related_types ? ['data' => ['#markup' => '• ' . implode('<br/>• ', $related_types)], 'nowrap' => 'nowrap'] : '<' . $this->t('none') . '>',
|
||||
$element_plugin_definition['provider'],
|
||||
$webform_element_plugin_definition['provider'],
|
||||
$operations ? ['data' => ['#type' => 'operations', '#links' => $operations]] : '',
|
||||
],
|
||||
];
|
||||
}
|
||||
else {
|
||||
$element_rows[$element_plugin_id] = [
|
||||
$element_plugin_id,
|
||||
$element_plugin_definition['provider'],
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
$build = [];
|
||||
|
||||
$build['filter'] = [
|
||||
'#type' => 'search',
|
||||
'#title' => $this->t('Filter'),
|
||||
'#title_display' => 'invisible',
|
||||
'#size' => 30,
|
||||
'#placeholder' => $this->t('Filter by element name'),
|
||||
'#attributes' => [
|
||||
'class' => ['webform-form-filter-text'],
|
||||
'data-element' => '.webform-element-plugin',
|
||||
'title' => $this->t('Enter a part of the element type to filter by.'),
|
||||
'autofocus' => 'autofocus',
|
||||
],
|
||||
];
|
||||
|
||||
ksort($webform_form_element_rows);
|
||||
$build['webform_elements'] = [
|
||||
'#type' => 'table',
|
||||
'#header' => [
|
||||
$this->t('Name'),
|
||||
$this->t('Label/Description'),
|
||||
$this->t('Class hierarchy'),
|
||||
$this->t('Webform info'),
|
||||
$this->t('Element info'),
|
||||
$this->t('Properties'),
|
||||
$this->t('Formats'),
|
||||
$this->t('Related'),
|
||||
$this->t('Provided by'),
|
||||
$this->t('Integrated by'),
|
||||
$this->t('Operations'),
|
||||
],
|
||||
'#rows' => $webform_form_element_rows,
|
||||
'#attributes' => [
|
||||
'class' => ['webform-element-plugin'],
|
||||
],
|
||||
];
|
||||
|
||||
ksort($element_rows);
|
||||
$build['elements'] = [
|
||||
'#type' => 'details',
|
||||
'#title' => $this->t('Additional elements'),
|
||||
'#description' => $this->t('Below are elements that are available but do not have a Webform Element integration plugin.'),
|
||||
'table' => [
|
||||
'#type' => 'table',
|
||||
'#header' => [
|
||||
$this->t('Name'),
|
||||
$this->t('Provided by'),
|
||||
],
|
||||
'#rows' => $element_rows,
|
||||
'#sticky' => TRUE,
|
||||
],
|
||||
];
|
||||
|
||||
$all_translatable_properties = $this->elementManager->getTranslatableProperties();
|
||||
$all_properties = $this->elementManager->getAllProperties();
|
||||
foreach ($all_translatable_properties as $key => $value) {
|
||||
$all_translatable_properties[$key] = [
|
||||
'#markup' => $value,
|
||||
'#prefix' => '<strong>',
|
||||
'#suffix' => '</strong>',
|
||||
'#weight' => -10,
|
||||
];
|
||||
}
|
||||
foreach ($all_properties as $key => $value) {
|
||||
// Remove all composite properties.
|
||||
if (strpos($key, '__')) {
|
||||
unset($all_properties[$key]);
|
||||
}
|
||||
}
|
||||
$build['properties'] = [
|
||||
'#type' => 'details',
|
||||
'#title' => $this->t('Element properties'),
|
||||
'#description' => $this->t('Below are all available element properties with translatable properties in <strong>bold</strong>.'),
|
||||
'list' => [
|
||||
'#theme' => 'item_list',
|
||||
'#items' => $all_translatable_properties + $all_properties,
|
||||
],
|
||||
];
|
||||
|
||||
$build['#attached']['library'][] = 'webform/webform.admin';
|
||||
$build['#attached']['library'][] = 'webform/webform.form';
|
||||
|
||||
return $build;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a class's name without its namespace.
|
||||
*
|
||||
* @param string $class
|
||||
* A class.
|
||||
*
|
||||
* @return string
|
||||
* The class's name without its namespace.
|
||||
*/
|
||||
protected function getClassName($class) {
|
||||
$parts = preg_split('#\\\\#', $class);
|
||||
return end($parts);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,72 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\webform\Controller;
|
||||
|
||||
use Drupal\Core\Controller\ControllerBase;
|
||||
use Drupal\Component\Plugin\PluginManagerInterface;
|
||||
use Drupal\Core\DependencyInjection\ContainerInjectionInterface;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
|
||||
/**
|
||||
* Controller for all results exporters.
|
||||
*/
|
||||
class WebformPluginExporterController extends ControllerBase implements ContainerInjectionInterface {
|
||||
|
||||
/**
|
||||
* A results exporter plugin manager.
|
||||
*
|
||||
* @var \Drupal\Component\Plugin\PluginManagerInterface
|
||||
*/
|
||||
protected $pluginManager;
|
||||
|
||||
/**
|
||||
* Constructs a WebformPluginExporterController object.
|
||||
*
|
||||
* @param \Drupal\Component\Plugin\PluginManagerInterface $plugin_manager
|
||||
* A results exporter plugin manager.
|
||||
*/
|
||||
public function __construct(PluginManagerInterface $plugin_manager) {
|
||||
$this->pluginManager = $plugin_manager;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function create(ContainerInterface $container) {
|
||||
return new static(
|
||||
$container->get('plugin.manager.webform.exporter')
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function index() {
|
||||
$definitions = $this->pluginManager->getDefinitions();
|
||||
$definitions = $this->pluginManager->getSortedDefinitions($definitions);
|
||||
|
||||
$rows = [];
|
||||
foreach ($definitions as $plugin_id => $definition) {
|
||||
$rows[$plugin_id] = [
|
||||
$plugin_id,
|
||||
$definition['label'],
|
||||
$definition['description'],
|
||||
$definition['provider'],
|
||||
];
|
||||
}
|
||||
|
||||
ksort($rows);
|
||||
return [
|
||||
'#type' => 'table',
|
||||
'#header' => [
|
||||
$this->t('ID'),
|
||||
$this->t('Label'),
|
||||
$this->t('Description'),
|
||||
$this->t('Provided by'),
|
||||
],
|
||||
'#rows' => $rows,
|
||||
'#sticky' => TRUE,
|
||||
];
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,175 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\webform\Controller;
|
||||
|
||||
use Drupal\Component\Plugin\PluginManagerInterface;
|
||||
use Drupal\Core\Controller\ControllerBase;
|
||||
use Drupal\Core\DependencyInjection\ContainerInjectionInterface;
|
||||
use Drupal\Core\Url;
|
||||
use Drupal\webform\Utility\WebformDialogHelper;
|
||||
use Drupal\webform\WebformHandlerInterface;
|
||||
use Drupal\webform\WebformInterface;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
|
||||
/**
|
||||
* Controller for all webform handlers.
|
||||
*/
|
||||
class WebformPluginHandlerController extends ControllerBase implements ContainerInjectionInterface {
|
||||
|
||||
/**
|
||||
* A webform handler plugin manager.
|
||||
*
|
||||
* @var \Drupal\Component\Plugin\PluginManagerInterface
|
||||
*/
|
||||
protected $pluginManager;
|
||||
|
||||
/**
|
||||
* Constructs a WebformPluginHanderController object.
|
||||
*
|
||||
* @param \Drupal\Component\Plugin\PluginManagerInterface $plugin_manager
|
||||
* A webform handler plugin manager.
|
||||
*/
|
||||
public function __construct(PluginManagerInterface $plugin_manager) {
|
||||
$this->pluginManager = $plugin_manager;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function create(ContainerInterface $container) {
|
||||
return new static(
|
||||
$container->get('plugin.manager.webform.handler')
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function index() {
|
||||
$definitions = $this->pluginManager->getDefinitions();
|
||||
$definitions = $this->pluginManager->getSortedDefinitions($definitions);
|
||||
|
||||
$rows = [];
|
||||
foreach ($definitions as $plugin_id => $definition) {
|
||||
$rows[$plugin_id] = [
|
||||
$plugin_id,
|
||||
$definition['label'],
|
||||
$definition['description'],
|
||||
$definition['category'],
|
||||
($definition['cardinality'] == -1) ? $this->t('Unlimited') : $definition['cardinality'],
|
||||
$definition['results'] ? $this->t('Processed') : $this->t('Ignored'),
|
||||
$definition['provider'],
|
||||
];
|
||||
}
|
||||
|
||||
ksort($rows);
|
||||
return [
|
||||
'#type' => 'table',
|
||||
'#header' => [
|
||||
$this->t('ID'),
|
||||
$this->t('Label'),
|
||||
$this->t('Description'),
|
||||
$this->t('Category'),
|
||||
$this->t('Cardinality'),
|
||||
$this->t('Results'),
|
||||
$this->t('Provided by'),
|
||||
],
|
||||
'#rows' => $rows,
|
||||
'#sticky' => TRUE,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Shows a list of webform handlers that can be added to a webform.
|
||||
*
|
||||
* @param \Symfony\Component\HttpFoundation\Request $request
|
||||
* The current request.
|
||||
* @param \Drupal\webform\WebformInterface $webform
|
||||
* A webform.
|
||||
*
|
||||
* @return array
|
||||
* A render array as expected by the renderer.
|
||||
*/
|
||||
public function listHandlers(Request $request, WebformInterface $webform) {
|
||||
$headers = [
|
||||
['data' => $this->t('Handler'), 'width' => '20%'],
|
||||
['data' => $this->t('Description'), 'width' => '40%'],
|
||||
['data' => $this->t('Category'), 'width' => '20%'],
|
||||
['data' => $this->t('Operations'), 'width' => '20%'],
|
||||
];
|
||||
|
||||
$definitions = $this->pluginManager->getDefinitions();
|
||||
$definitions = $this->pluginManager->getSortedDefinitions($definitions);
|
||||
|
||||
$rows = [];
|
||||
foreach ($definitions as $plugin_id => $definition) {
|
||||
// Skip email handler which has dedicated button.
|
||||
if ($plugin_id == 'email') {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Check cardinality.
|
||||
$cardinality = $definition['cardinality'];
|
||||
$is_cardinality_unlimited = ($cardinality == WebformHandlerInterface::CARDINALITY_UNLIMITED);
|
||||
$is_cardinality_reached = ($webform->getHandlers($plugin_id)->count() >= $cardinality);
|
||||
if (!$is_cardinality_unlimited && $is_cardinality_reached) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$row = [];
|
||||
$row['title']['data'] = [
|
||||
'#type' => 'inline_template',
|
||||
'#template' => '<div class="webform-form-filter-text-source">{{ label }}</div>',
|
||||
'#context' => [
|
||||
'label' => $definition['label'],
|
||||
],
|
||||
];
|
||||
$row['description'] = [
|
||||
'data' => [
|
||||
'#markup' => $definition['description'],
|
||||
],
|
||||
];
|
||||
$row['category'] = $definition['category'];
|
||||
$links['add'] = [
|
||||
'title' => $this->t('Add handler'),
|
||||
'url' => Url::fromRoute('entity.webform.handler.add_form', ['webform' => $webform->id(), 'webform_handler' => $plugin_id]),
|
||||
'attributes' => WebformDialogHelper::getModalDialogAttributes(800),
|
||||
];
|
||||
$row['operations']['data'] = [
|
||||
'#type' => 'operations',
|
||||
'#links' => $links,
|
||||
];
|
||||
$rows[] = $row;
|
||||
}
|
||||
|
||||
$build['#attached']['library'][] = 'webform/webform.form';
|
||||
|
||||
$build['filter'] = [
|
||||
'#type' => 'search',
|
||||
'#title' => $this->t('Filter'),
|
||||
'#title_display' => 'invisible',
|
||||
'#size' => 30,
|
||||
'#placeholder' => $this->t('Filter by handler name'),
|
||||
'#attributes' => [
|
||||
'class' => ['webform-form-filter-text'],
|
||||
'data-element' => '.webform-handler-add-table',
|
||||
'title' => $this->t('Enter a part of the handler name to filter by.'),
|
||||
'autofocus' => 'autofocus',
|
||||
],
|
||||
];
|
||||
|
||||
$build['handlers'] = [
|
||||
'#type' => 'table',
|
||||
'#header' => $headers,
|
||||
'#rows' => $rows,
|
||||
'#empty' => $this->t('No handler available.'),
|
||||
'#attributes' => [
|
||||
'class' => ['webform-handler-add-table'],
|
||||
],
|
||||
];
|
||||
|
||||
return $build;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,368 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\webform\Controller;
|
||||
|
||||
use Drupal\Core\Controller\ControllerBase;
|
||||
use Drupal\Core\DependencyInjection\ContainerInjectionInterface;
|
||||
use Drupal\Core\Entity\EntityInterface;
|
||||
use Drupal\Core\Url;
|
||||
use Drupal\webform\Entity\Webform;
|
||||
use Drupal\webform\Entity\WebformSubmission;
|
||||
use Drupal\webform\WebformInterface;
|
||||
use Drupal\webform\WebformRequestInterface;
|
||||
use Drupal\webform\WebformSubmissionExporterInterface;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
use Symfony\Component\HttpFoundation\File\MimeType\MimeTypeGuesserInterface;
|
||||
use Symfony\Component\HttpFoundation\RedirectResponse;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
|
||||
/**
|
||||
* Controller routines for webform submission export.
|
||||
*/
|
||||
class WebformResultsExportController extends ControllerBase implements ContainerInjectionInterface {
|
||||
|
||||
/**
|
||||
* The MIME type guesser.
|
||||
*
|
||||
* @var \Symfony\Component\HttpFoundation\File\MimeType\MimeTypeGuesserInterface
|
||||
*/
|
||||
protected $mimeTypeGuesser;
|
||||
|
||||
/**
|
||||
* The webform submission exporter.
|
||||
*
|
||||
* @var \Drupal\webform\WebformSubmissionExporterInterface
|
||||
*/
|
||||
protected $submissionExporter;
|
||||
|
||||
/**
|
||||
* Webform request handler.
|
||||
*
|
||||
* @var \Drupal\webform\WebformRequestInterface
|
||||
*/
|
||||
protected $requestHandler;
|
||||
|
||||
/**
|
||||
* Constructs a WebformResultsExportController object.
|
||||
*
|
||||
* @param \Symfony\Component\HttpFoundation\File\MimeType\MimeTypeGuesserInterface $mime_type_guesser
|
||||
* The MIME type guesser instance to use.
|
||||
* @param \Drupal\webform\WebformSubmissionExporterInterface $webform_submission_exporter
|
||||
* The webform submission exported.
|
||||
* @param \Drupal\webform\WebformRequestInterface $request_handler
|
||||
* The webform request handler.
|
||||
*/
|
||||
public function __construct(MimeTypeGuesserInterface $mime_type_guesser, WebformSubmissionExporterInterface $webform_submission_exporter, WebformRequestInterface $request_handler) {
|
||||
$this->mimeTypeGuesser = $mime_type_guesser;
|
||||
$this->submissionExporter = $webform_submission_exporter;
|
||||
$this->requestHandler = $request_handler;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function create(ContainerInterface $container) {
|
||||
return new static(
|
||||
$container->get('file.mime_type.guesser'),
|
||||
$container->get('webform_submission.exporter'),
|
||||
$container->get('webform.request')
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns webform submission as a CSV.
|
||||
*
|
||||
* @param \Symfony\Component\HttpFoundation\Request $request
|
||||
* The current request.
|
||||
*
|
||||
* @return array|null|\Symfony\Component\HttpFoundation\RedirectResponse|\Symfony\Component\HttpFoundation\Response
|
||||
* A response that renders or redirects to the CSV file.
|
||||
*/
|
||||
public function index(Request $request) {
|
||||
list($webform, $source_entity) = $this->requestHandler->getWebformEntities();
|
||||
$this->submissionExporter->setWebform($webform);
|
||||
$this->submissionExporter->setSourceEntity($source_entity);
|
||||
|
||||
$query = $request->query->all();
|
||||
unset($query['destination']);
|
||||
if (isset($query['filename'])) {
|
||||
$build = $this->formBuilder()->getForm('Drupal\webform\Form\WebformResultsExportForm');
|
||||
|
||||
// Redirect to file export.
|
||||
$file_path = $this->submissionExporter->getFileTempDirectory() . '/' . $query['filename'];
|
||||
if (file_exists($file_path)) {
|
||||
$route_name = $this->requestHandler->getRouteName($webform, $source_entity, 'webform.results_export_file');
|
||||
$route_parameters = $this->requestHandler->getRouteParameters($webform, $source_entity) + ['filename' => $query['filename']];
|
||||
$file_url = Url::fromRoute($route_name, $route_parameters, ['absolute' => TRUE])->toString();
|
||||
drupal_set_message($this->t('Export creation complete. Your download should begin now. If it does not start, <a href=":href">download the file here</a>. This file may only be downloaded once.', [':href' => $file_url]));
|
||||
$build['#attached']['html_head'][] = [
|
||||
[
|
||||
'#tag' => 'meta',
|
||||
'#attributes' => [
|
||||
'http-equiv' => 'refresh',
|
||||
'content' => '0; url=' . $file_url,
|
||||
],
|
||||
],
|
||||
'webform_results_export_download_file_refresh',
|
||||
];
|
||||
}
|
||||
|
||||
return $build;
|
||||
}
|
||||
elseif ($query && empty($query['ajax_form'])) {
|
||||
if (!empty($query['excluded_columns']) && is_string($query['excluded_columns'])) {
|
||||
$excluded_columns = explode(',', $query['excluded_columns']);
|
||||
$query['excluded_columns'] = array_combine($excluded_columns, $excluded_columns);
|
||||
}
|
||||
|
||||
$export_options = $query + $this->submissionExporter->getDefaultExportOptions();
|
||||
$this->submissionExporter->setExporter($export_options);
|
||||
if ($this->submissionExporter->isBatch()) {
|
||||
self::batchSet($webform, $source_entity, $export_options);
|
||||
$route_name = $this->requestHandler->getRouteName($webform, $source_entity, 'webform.results_export');
|
||||
$route_parameters = $this->requestHandler->getRouteParameters($webform, $source_entity);
|
||||
return batch_process(Url::fromRoute($route_name, $route_parameters));
|
||||
}
|
||||
else {
|
||||
$this->submissionExporter->generate();
|
||||
$file_path = $this->submissionExporter->getExportFilePath();
|
||||
return $this->downloadFile($file_path, $export_options['download']);
|
||||
}
|
||||
|
||||
}
|
||||
else {
|
||||
return $this->formBuilder()->getForm('Drupal\webform\Form\WebformResultsExportForm', $webform);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns webform submission results as CSV file.
|
||||
*
|
||||
* @param \Symfony\Component\HttpFoundation\Request $request
|
||||
* The current request.
|
||||
* @param string $filename
|
||||
* CSV file name.
|
||||
*
|
||||
* @return array|\Symfony\Component\HttpFoundation\Response
|
||||
* A response that renders or redirects to the CSV file.
|
||||
*/
|
||||
public function file(Request $request, $filename) {
|
||||
list($webform, $source_entity) = $this->requestHandler->getWebformEntities();
|
||||
$this->submissionExporter->setWebform($webform);
|
||||
$this->submissionExporter->setSourceEntity($source_entity);
|
||||
|
||||
$file_path = $this->submissionExporter->getFileTempDirectory() . '/' . $filename;
|
||||
if (!file_exists($file_path)) {
|
||||
$route_name = $this->requestHandler->getRouteName($webform, $source_entity, 'webform.results_export');
|
||||
$route_parameters = $this->requestHandler->getRouteParameters($webform, $source_entity);
|
||||
$t_args = [
|
||||
':href' => Url::fromRoute($route_name, $route_parameters)->toString(),
|
||||
];
|
||||
$build = [
|
||||
'#markup' => $this->t('No export file ready for download. The file may have already been downloaded by your browser. Visit the <a href=":href">download export webform</a> to create a new export.', $t_args),
|
||||
];
|
||||
return $build;
|
||||
}
|
||||
else {
|
||||
return $this->downloadFile($file_path);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Download generated CSV file.
|
||||
*
|
||||
* @param string $file_path
|
||||
* The paths the generate CSV file.
|
||||
* @param bool $download
|
||||
* Download the generated CSV file. Default to TRUE.
|
||||
*
|
||||
* @return \Symfony\Component\HttpFoundation\Response
|
||||
* A response object containing the CSV file.
|
||||
*/
|
||||
public function downloadFile($file_path, $download = TRUE) {
|
||||
// Return the export file.
|
||||
$contents = file_get_contents($file_path);
|
||||
unlink($file_path);
|
||||
|
||||
$content_type = $this->mimeTypeGuesser->guess($file_path);
|
||||
|
||||
if ($download) {
|
||||
$headers = [
|
||||
'Content-Length' => strlen($contents),
|
||||
'Content-Type' => $content_type,
|
||||
'Content-Disposition' => 'attachment; filename="' . basename($file_path) . '"',
|
||||
];
|
||||
}
|
||||
else {
|
||||
if ($content_type != 'text/html') {
|
||||
$content_type = 'text/plain';
|
||||
}
|
||||
$headers = [
|
||||
'Content-Length' => strlen($contents),
|
||||
'Content-Type' => $content_type . '; charset=utf-8',
|
||||
];
|
||||
}
|
||||
|
||||
return new Response($contents, 200, $headers);
|
||||
}
|
||||
|
||||
/****************************************************************************/
|
||||
// Batch functions.
|
||||
// Using static method to prevent the service container from being serialized.
|
||||
// "Prevents exception 'AssertionError' with message 'The container was serialized.'."
|
||||
/****************************************************************************/
|
||||
|
||||
/**
|
||||
* Batch API; Initialize batch operations.
|
||||
*
|
||||
* @param \Drupal\webform\WebformInterface|null $webform
|
||||
* A webform.
|
||||
* @param \Drupal\Core\Entity\EntityInterface|null $source_entity
|
||||
* A webform source entity.
|
||||
* @param array $export_options
|
||||
* An array of export options.
|
||||
*
|
||||
* @see http://www.jeffgeerling.com/blogs/jeff-geerling/using-batch-api-build-huge-csv
|
||||
*/
|
||||
public static function batchSet(WebformInterface $webform, EntityInterface $source_entity = NULL, array $export_options) {
|
||||
if (!empty($export_options['excluded_columns']) && is_string($export_options['excluded_columns'])) {
|
||||
$excluded_columns = explode(',', $export_options['excluded_columns']);
|
||||
$export_options['excluded_columns'] = array_combine($excluded_columns, $excluded_columns);
|
||||
}
|
||||
|
||||
/** @var \Drupal\webform\WebformSubmissionExporterInterface $submission_exporter */
|
||||
$submission_exporter = \Drupal::service('webform_submission.exporter');
|
||||
$submission_exporter->setWebform($webform);
|
||||
$submission_exporter->setSourceEntity($source_entity);
|
||||
$submission_exporter->setExporter($export_options);
|
||||
|
||||
$parameters = [
|
||||
$webform,
|
||||
$source_entity,
|
||||
$export_options,
|
||||
];
|
||||
$batch = [
|
||||
'title' => t('Exporting submissions'),
|
||||
'init_message' => t('Creating export file'),
|
||||
'error_message' => t('The export file could not be created because an error occurred.'),
|
||||
'operations' => [
|
||||
[['\Drupal\webform\Controller\WebformResultsExportController', 'batchProcess'], $parameters],
|
||||
],
|
||||
'finished' => ['\Drupal\webform\Controller\WebformResultsExportController', 'batchFinish'],
|
||||
];
|
||||
|
||||
batch_set($batch);
|
||||
}
|
||||
|
||||
/**
|
||||
* Batch API callback; Write the header and rows of the export to the export file.
|
||||
*
|
||||
* @param \Drupal\webform\WebformInterface $webform
|
||||
* The webform.
|
||||
* @param \Drupal\Core\Entity\EntityInterface|null $source_entity
|
||||
* A webform source entity.
|
||||
* @param array $export_options
|
||||
* An associative array of export options.
|
||||
* @param mixed|array $context
|
||||
* The batch current context.
|
||||
*/
|
||||
public static function batchProcess(WebformInterface $webform, EntityInterface $source_entity = NULL, array $export_options, &$context) {
|
||||
/** @var \Drupal\webform\WebformSubmissionExporterInterface $submission_exporter */
|
||||
$submission_exporter = \Drupal::service('webform_submission.exporter');
|
||||
$submission_exporter->setWebform($webform);
|
||||
$submission_exporter->setSourceEntity($source_entity);
|
||||
$submission_exporter->setExporter($export_options);
|
||||
|
||||
if (empty($context['sandbox'])) {
|
||||
$context['sandbox']['progress'] = 0;
|
||||
$context['sandbox']['current_sid'] = 0;
|
||||
$context['sandbox']['max'] = $submission_exporter->getQuery()->count()->execute();
|
||||
// Store entity ids and not the actual webform or source entity in the
|
||||
// $context to prevent "The container was serialized" errors.
|
||||
// @see https://www.drupal.org/node/2822023
|
||||
$context['results']['webform_id'] = $webform->id();
|
||||
$context['results']['source_entity_type'] = ($source_entity) ? $source_entity->getEntityTypeId() : NULL;
|
||||
$context['results']['source_entity_id'] = ($source_entity) ? $source_entity->id() : NULL;
|
||||
$context['results']['export_options'] = $export_options;
|
||||
$submission_exporter->writeHeader();
|
||||
}
|
||||
|
||||
// Write CSV records.
|
||||
$query = $submission_exporter->getQuery();
|
||||
$query->condition('sid', $context['sandbox']['current_sid'], '>');
|
||||
$query->range(0, $submission_exporter->getBatchLimit());
|
||||
$entity_ids = $query->execute();
|
||||
$webform_submissions = WebformSubmission::loadMultiple($entity_ids);
|
||||
$submission_exporter->writeRecords($webform_submissions);
|
||||
|
||||
// Track progress.
|
||||
$context['sandbox']['progress'] += count($webform_submissions);
|
||||
$context['sandbox']['current_sid'] = ($webform_submissions) ? end($webform_submissions)->id() : 0;
|
||||
|
||||
$context['message'] = t('Exported @count of @total submissions...', ['@count' => $context['sandbox']['progress'], '@total' => $context['sandbox']['max']]);
|
||||
|
||||
// Track finished.
|
||||
if ($context['sandbox']['progress'] != $context['sandbox']['max']) {
|
||||
$context['finished'] = $context['sandbox']['progress'] / $context['sandbox']['max'];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Batch API callback; Completed export.
|
||||
*
|
||||
* @param bool $success
|
||||
* TRUE if batch successfully completed.
|
||||
* @param array $results
|
||||
* Batch results.
|
||||
* @param array $operations
|
||||
* An array of function calls (not used in this function).
|
||||
*
|
||||
* @return \Symfony\Component\HttpFoundation\RedirectResponse
|
||||
* Redirect to download the exported results.
|
||||
*/
|
||||
public static function batchFinish($success, array $results, array $operations) {
|
||||
$webform_id = $results['webform_id'];
|
||||
$entity_type = $results['source_entity_type'];
|
||||
$entity_id = $results['source_entity_id'];
|
||||
|
||||
/** @var \Drupal\webform\WebformInterface $webform */
|
||||
$webform = Webform::load($webform_id);
|
||||
/** @var \Drupal\Core\Entity\EntityInterface|null $source_entity */
|
||||
$source_entity = ($entity_type && $entity_id) ? \Drupal::entityTypeManager()->getStorage($entity_type)->load($entity_id) : NULL;
|
||||
/** @var array $export_options */
|
||||
$export_options = $results['export_options'];
|
||||
|
||||
/** @var \Drupal\webform\WebformSubmissionExporterInterface $submission_exporter */
|
||||
$submission_exporter = \Drupal::service('webform_submission.exporter');
|
||||
$submission_exporter->setWebform($webform);
|
||||
$submission_exporter->setSourceEntity($source_entity);
|
||||
$submission_exporter->setExporter($export_options);
|
||||
|
||||
if (!$success) {
|
||||
$file_path = $submission_exporter->getExportFilePath();
|
||||
@unlink($file_path);
|
||||
$archive_path = $submission_exporter->getArchiveFilePath();
|
||||
@unlink($archive_path);
|
||||
drupal_set_message(t('Finished with an error.'));
|
||||
}
|
||||
else {
|
||||
$submission_exporter->writeFooter();
|
||||
|
||||
$filename = $submission_exporter->getExportFileName();
|
||||
|
||||
if ($submission_exporter->isArchive()) {
|
||||
$submission_exporter->writeExportToArchive();
|
||||
$filename = $submission_exporter->getArchiveFileName();
|
||||
}
|
||||
|
||||
/** @var \Drupal\webform\WebformRequestInterface $request_handler */
|
||||
$request_handler = \Drupal::service('webform.request');
|
||||
$route_name = $request_handler->getRouteName($webform, $source_entity, 'webform.results_export');
|
||||
$route_parameters = $request_handler->getRouteParameters($webform, $source_entity);
|
||||
$redirect_url = Url::fromRoute($route_name, $route_parameters, ['query' => ['filename' => $filename], 'absolute' => TRUE]);
|
||||
return new RedirectResponse($redirect_url->toString());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,144 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\webform\Controller;
|
||||
|
||||
use Drupal\Component\Render\FormattableMarkup;
|
||||
use Drupal\Core\Ajax\AjaxResponse;
|
||||
use Drupal\Core\Ajax\HtmlCommand;
|
||||
use Drupal\Core\Controller\ControllerBase;
|
||||
use Drupal\Core\DependencyInjection\ContainerInjectionInterface;
|
||||
use Drupal\webform\WebformSubmissionInterface;
|
||||
use Drupal\webform\WebformRequestInterface;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
|
||||
/**
|
||||
* Provides route responses for webform submissions.
|
||||
*/
|
||||
class WebformSubmissionController extends ControllerBase implements ContainerInjectionInterface {
|
||||
|
||||
/**
|
||||
* Webform request handler.
|
||||
*
|
||||
* @var \Drupal\webform\WebformRequestInterface
|
||||
*/
|
||||
protected $requestHandler;
|
||||
|
||||
/**
|
||||
* Constructs a WebformSubmissionController object.
|
||||
*
|
||||
* @param \Drupal\webform\WebformRequestInterface $request_handler
|
||||
* The webform request handler.
|
||||
*/
|
||||
public function __construct(WebformRequestInterface $request_handler) {
|
||||
$this->requestHandler = $request_handler;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function create(ContainerInterface $container) {
|
||||
return new static(
|
||||
$container->get('webform.request')
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a webform submission in a specified format type.
|
||||
*
|
||||
* @param \Drupal\webform\WebformSubmissionInterface $webform_submission
|
||||
* A webform submission.
|
||||
* @param string $type
|
||||
* The format type.
|
||||
*
|
||||
* @return array
|
||||
* A render array representing a webform submission in a specified format
|
||||
* type.
|
||||
*/
|
||||
public function index(WebformSubmissionInterface $webform_submission, $type) {
|
||||
if ($type == 'default') {
|
||||
$type = 'html';
|
||||
}
|
||||
|
||||
$build = [];
|
||||
$source_entity = $this->requestHandler->getCurrentSourceEntity('webform_submission');
|
||||
// Navigation.
|
||||
$build['navigation'] = [
|
||||
'#theme' => 'webform_submission_navigation',
|
||||
'#webform_submission' => $webform_submission,
|
||||
];
|
||||
|
||||
// Information.
|
||||
$build['information'] = [
|
||||
'#theme' => 'webform_submission_information',
|
||||
'#webform_submission' => $webform_submission,
|
||||
'#source_entity' => $source_entity,
|
||||
];
|
||||
|
||||
// Submission.
|
||||
$build['submission'] = [
|
||||
'#theme' => 'webform_submission_' . $type,
|
||||
'#webform_submission' => $webform_submission,
|
||||
'#source_entity' => $source_entity,
|
||||
];
|
||||
|
||||
// Wrap plain text and YAML in CodeMirror view widget.
|
||||
if (in_array($type, ['text', 'yaml'])) {
|
||||
$build['submission'] = [
|
||||
'#theme' => 'webform_codemirror',
|
||||
'#code' => $build['submission'],
|
||||
'#type' => $type,
|
||||
];
|
||||
}
|
||||
|
||||
$build['#attached']['library'][] = 'webform/webform.admin';
|
||||
|
||||
return $build;
|
||||
}
|
||||
|
||||
/**
|
||||
* Toggle webform submission sticky.
|
||||
*
|
||||
* @param \Drupal\webform\WebformSubmissionInterface $webform_submission
|
||||
* A webform submission.
|
||||
*
|
||||
* @return \Drupal\Core\Ajax\AjaxResponse
|
||||
* An AJAX response that toggle the sticky icon.
|
||||
*/
|
||||
public function sticky(WebformSubmissionInterface $webform_submission) {
|
||||
// Toggle sticky.
|
||||
$webform_submission->setSticky(!$webform_submission->isSticky())->save();
|
||||
|
||||
// Get state.
|
||||
$state = $webform_submission->isSticky() ? 'on' : 'off';
|
||||
|
||||
$response = new AjaxResponse();
|
||||
$response->addCommand(new HtmlCommand(
|
||||
'#webform-submission-' . $webform_submission->id() . '-sticky',
|
||||
new FormattableMarkup('<span class="webform-icon webform-icon-sticky webform-icon-sticky--@state"></span>', ['@state' => $state])
|
||||
));
|
||||
return $response;
|
||||
}
|
||||
|
||||
/**
|
||||
* Route title callback.
|
||||
*
|
||||
* @param \Drupal\webform\WebformSubmissionInterface $webform_submission
|
||||
* The webform submission.
|
||||
* @param bool $duplicate
|
||||
* Flag indicating if submission is being duplicated.
|
||||
*
|
||||
* @return array
|
||||
* The webform submission as a render array.
|
||||
*/
|
||||
public function title(WebformSubmissionInterface $webform_submission, $duplicate = FALSE) {
|
||||
$source_entity = $this->requestHandler->getCurrentSourceEntity('webform_submission');
|
||||
$t_args = [
|
||||
'@form' => ($source_entity) ? $source_entity->label() : $webform_submission->getWebform()->label(),
|
||||
'@id' => $webform_submission->serial(),
|
||||
];
|
||||
|
||||
$title = $this->t('@form: Submission #@id', $t_args);
|
||||
return ($duplicate) ? $this->t('Duplicate @title', ['@title' => $title]) : $title;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,102 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\webform\Controller;
|
||||
|
||||
use Drupal\Core\Controller\ControllerBase;
|
||||
use Drupal\Core\DependencyInjection\ContainerInjectionInterface;
|
||||
use Drupal\webform\WebformInterface;
|
||||
use Drupal\webform\WebformRequestInterface;
|
||||
use Drupal\webform\WebformSubmissionGenerateInterface;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
|
||||
/**
|
||||
* Provides route responses for webform testing.
|
||||
*/
|
||||
class WebformTestController extends ControllerBase implements ContainerInjectionInterface {
|
||||
|
||||
/**
|
||||
* Webform request handler.
|
||||
*
|
||||
* @var \Drupal\webform\WebformRequestInterface
|
||||
*/
|
||||
protected $requestHandler;
|
||||
|
||||
/**
|
||||
* Webform submission generation service.
|
||||
*
|
||||
* @var \Drupal\webform\WebformSubmissionGenerateInterface
|
||||
*/
|
||||
protected $generate;
|
||||
|
||||
/**
|
||||
* Constructs a WebformTestController object.
|
||||
*
|
||||
* @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) {
|
||||
$this->requestHandler = $request_handler;
|
||||
$this->generate = $submission_generate;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function create(ContainerInterface $container) {
|
||||
return new static(
|
||||
$container->get('webform.request'),
|
||||
$container->get('webform_submission.generate')
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a webform to add a new test submission to a webform.
|
||||
*
|
||||
* @param \Symfony\Component\HttpFoundation\Request $request
|
||||
* The current request.
|
||||
*
|
||||
* @return array
|
||||
* The webform submission webform.
|
||||
*/
|
||||
public function testForm(Request $request) {
|
||||
/** @var \Drupal\webform\WebformInterface $webform */
|
||||
/** @var \Drupal\Core\Entity\EntityInterface $source_entity */
|
||||
list($webform, $source_entity) = $this->requestHandler->getWebformEntities();
|
||||
$values = [];
|
||||
|
||||
// Set source entity type and id.
|
||||
if ($source_entity) {
|
||||
$values['entity_type'] = $source_entity->getEntityTypeId();
|
||||
$values['entity_id'] = $source_entity->id();
|
||||
}
|
||||
|
||||
if ($request->query->get('webform_id') == $webform->id()) {
|
||||
return $webform->getSubmissionForm($values);
|
||||
}
|
||||
|
||||
// Generate date.
|
||||
$values['data'] = $this->generate->getData($webform);
|
||||
|
||||
return $webform->getSubmissionForm($values);
|
||||
}
|
||||
|
||||
/**
|
||||
* Route title callback.
|
||||
*
|
||||
* @param \Drupal\webform\WebformInterface $webform
|
||||
* The webform.
|
||||
*
|
||||
* @return string
|
||||
* The webform label as a render array.
|
||||
*/
|
||||
public function title(WebformInterface $webform) {
|
||||
/** @var \Drupal\webform\WebformInterface $webform */
|
||||
/** @var \Drupal\Core\Entity\EntityInterface $source_entity */
|
||||
list($webform, $source_entity) = $this->requestHandler->getWebformEntities();
|
||||
return $this->t('Testing %title webform', ['%title' => ($source_entity) ? $source_entity->label() : $webform->label()]);
|
||||
}
|
||||
|
||||
}
|
||||
44
web/modules/contrib/webform/src/Element/Webform.php
Normal file
44
web/modules/contrib/webform/src/Element/Webform.php
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\webform\Element;
|
||||
|
||||
use Drupal\Core\Render\Element\RenderElement;
|
||||
use Drupal\webform\Entity\Webform as WebformEntity;
|
||||
use Drupal\webform\WebformInterface;
|
||||
|
||||
/**
|
||||
* Provides a render element to display a webform.
|
||||
*
|
||||
* @RenderElement("webform")
|
||||
*/
|
||||
class Webform extends RenderElement {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getInfo() {
|
||||
$class = get_class($this);
|
||||
return [
|
||||
'#pre_render' => [
|
||||
[$class, 'preRenderWebformElement'],
|
||||
],
|
||||
'#webform' => NULL,
|
||||
'#default_data' => [],
|
||||
'#cache' => ['max-age' => 0],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Webform element pre render callback.
|
||||
*/
|
||||
public static function preRenderWebformElement($element) {
|
||||
$webform = ($element['#webform'] instanceof WebformInterface) ? $element['#webform'] : WebformEntity::load($element['#webform']);
|
||||
if (!$webform || !$webform->access('submission_create')) {
|
||||
return $element;
|
||||
}
|
||||
|
||||
$values = ['data' => $element['#default_data']];
|
||||
return $element + $webform->getSubmissionForm($values);
|
||||
}
|
||||
|
||||
}
|
||||
46
web/modules/contrib/webform/src/Element/WebformAddress.php
Normal file
46
web/modules/contrib/webform/src/Element/WebformAddress.php
Normal file
|
|
@ -0,0 +1,46 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\webform\Element;
|
||||
|
||||
/**
|
||||
* Provides a webform element for an address element.
|
||||
*
|
||||
* @FormElement("webform_address")
|
||||
*/
|
||||
class WebformAddress extends WebformCompositeBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function getCompositeElements() {
|
||||
$elements = [];
|
||||
$elements['address'] = [
|
||||
'#type' => 'textfield',
|
||||
'#title' => t('Address'),
|
||||
];
|
||||
$elements['address_2'] = [
|
||||
'#type' => 'textfield',
|
||||
'#title' => t('Address 2'),
|
||||
];
|
||||
$elements['city'] = [
|
||||
'#type' => 'textfield',
|
||||
'#title' => t('City/Town'),
|
||||
];
|
||||
$elements['state_province'] = [
|
||||
'#type' => 'select',
|
||||
'#title' => t('State/Province'),
|
||||
'#options' => 'state_province_names',
|
||||
];
|
||||
$elements['postal_code'] = [
|
||||
'#type' => 'textfield',
|
||||
'#title' => t('Zip/Postal Code'),
|
||||
];
|
||||
$elements['country'] = [
|
||||
'#type' => 'select',
|
||||
'#title' => t('Country'),
|
||||
'#options' => 'country_names',
|
||||
];
|
||||
return $elements;
|
||||
}
|
||||
|
||||
}
|
||||
17
web/modules/contrib/webform/src/Element/WebformAudioFile.php
Normal file
17
web/modules/contrib/webform/src/Element/WebformAudioFile.php
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\webform\Element;
|
||||
|
||||
/**
|
||||
* Provides a webform element for an 'audio_file' element.
|
||||
*
|
||||
* @FormElement("webform_audio_file")
|
||||
*/
|
||||
class WebformAudioFile extends WebformManagedFileBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $accept = 'audio/*';
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\webform\Element;
|
||||
|
||||
use Drupal\Core\Render\Element\Textfield;
|
||||
|
||||
/**
|
||||
* Provides a one-line text field with autocompletion webform element.
|
||||
*
|
||||
* @FormElement("webform_autocomplete")
|
||||
*/
|
||||
class WebformAutocomplete extends Textfield {}
|
||||
27
web/modules/contrib/webform/src/Element/WebformButtons.php
Normal file
27
web/modules/contrib/webform/src/Element/WebformButtons.php
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\webform\Element;
|
||||
|
||||
use Drupal\Core\Form\FormStateInterface;
|
||||
use Drupal\Core\Render\Element\Radios;
|
||||
|
||||
/**
|
||||
* Provides a webform element for buttons with an other option.
|
||||
*
|
||||
* @FormElement("webform_buttons")
|
||||
*/
|
||||
class WebformButtons extends Radios {
|
||||
|
||||
/**
|
||||
* Expands a radios element into individual radio elements.
|
||||
*/
|
||||
public static function processRadios(&$element, FormStateInterface $form_state, &$complete_form) {
|
||||
$element = parent::processRadios($element, $form_state, $complete_form);
|
||||
$element['#attached']['library'][] = 'webform/webform.element.buttons';
|
||||
$element['#attributes']['class'][] = 'js-webform-buttons';
|
||||
$element['#attributes']['class'][] = 'webform-buttons';
|
||||
$element['#options_display'] = 'side_by_side';
|
||||
return $element;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,31 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\webform\Element;
|
||||
|
||||
use Drupal\Core\Form\FormStateInterface;
|
||||
|
||||
/**
|
||||
* Provides a webform element for buttons with an other option.
|
||||
*
|
||||
* @FormElement("webform_buttons_other")
|
||||
*/
|
||||
class WebformButtonsOther extends WebformOtherBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $type = 'webform_buttons';
|
||||
|
||||
/**
|
||||
* Processes an 'other' element.
|
||||
*
|
||||
* See select list webform element for select list properties.
|
||||
*
|
||||
* @see \Drupal\Core\Render\Element\Select
|
||||
*/
|
||||
public static function processWebformOther(&$element, FormStateInterface $form_state, &$complete_form) {
|
||||
$element = parent::processWebformOther($element, $form_state, $complete_form);
|
||||
return $element;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\webform\Element;
|
||||
|
||||
/**
|
||||
* Provides a webform element for checkboxes with an other option.
|
||||
*
|
||||
* @FormElement("webform_checkboxes_other")
|
||||
*/
|
||||
class WebformCheckboxesOther extends WebformOtherBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $type = 'checkboxes';
|
||||
|
||||
}
|
||||
201
web/modules/contrib/webform/src/Element/WebformCodeMirror.php
Normal file
201
web/modules/contrib/webform/src/Element/WebformCodeMirror.php
Normal file
|
|
@ -0,0 +1,201 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\webform\Element;
|
||||
|
||||
use Drupal\Core\Serialization\Yaml;
|
||||
use Drupal\Core\Render\Element\Textarea;
|
||||
use Drupal\Core\Form\FormStateInterface;
|
||||
use Drupal\webform\Utility\WebformYaml;
|
||||
|
||||
/**
|
||||
* Provides a webform element for HTML, YAML, or Plain text using CodeMirror.
|
||||
*
|
||||
* @FormElement("webform_codemirror")
|
||||
*/
|
||||
class WebformCodeMirror extends Textarea {
|
||||
|
||||
/**
|
||||
* An associative array of supported CodeMirror modes by type and mime-type.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected static $modes = [
|
||||
'css' => 'text/css',
|
||||
'html' => 'text/html',
|
||||
'javascript' => 'text/javascript',
|
||||
'text' => 'text/plain',
|
||||
'yaml' => 'text/x-yaml',
|
||||
];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getInfo() {
|
||||
$class = get_class($this);
|
||||
return [
|
||||
'#input' => TRUE,
|
||||
'#mode' => 'text',
|
||||
'#skip_validation' => FALSE,
|
||||
'#cols' => 60,
|
||||
'#rows' => 5,
|
||||
'#resizable' => 'vertical',
|
||||
'#process' => [
|
||||
[$class, 'processWebformCodeMirror'],
|
||||
[$class, 'processAjaxForm'],
|
||||
[$class, 'processGroup'],
|
||||
],
|
||||
'#pre_render' => [
|
||||
[$class, 'preRenderWebformCodeMirror'],
|
||||
[$class, 'preRenderGroup'],
|
||||
],
|
||||
'#theme' => 'textarea',
|
||||
'#theme_wrappers' => ['form_element'],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function valueCallback(&$element, $input, FormStateInterface $form_state) {
|
||||
if ($input === FALSE && $element['#mode'] == 'yaml' && isset($element['#default_value'])) {
|
||||
// Convert associative array in default value to YAML.
|
||||
if (is_array($element['#default_value'])) {
|
||||
$element['#default_value'] = WebformYaml::tidy(Yaml::encode($element['#default_value']));
|
||||
}
|
||||
// Convert empty YAML into an empty string.
|
||||
if ($element['#default_value'] == '{ }') {
|
||||
$element['#default_value'] = '';
|
||||
}
|
||||
return $element['#default_value'];
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Processes a 'webform_codemirror' element.
|
||||
*/
|
||||
public static function processWebformCodeMirror(&$element, FormStateInterface $form_state, &$complete_form) {
|
||||
// Check that mode is defined and valid, if not default to (plain) text.
|
||||
if (empty($element['#mode']) || !isset(self::$modes[$element['#mode']])) {
|
||||
$element['#mode'] = 'text';
|
||||
}
|
||||
|
||||
// Set validation.
|
||||
if (isset($element['#element_validate'])) {
|
||||
$element['#element_validate'] = array_merge([[get_called_class(), 'validateWebformCodeMirror']], $element['#element_validate']);
|
||||
}
|
||||
else {
|
||||
$element['#element_validate'] = [[get_called_class(), 'validateWebformCodeMirror']];
|
||||
}
|
||||
|
||||
return $element;
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepares a #type 'webform_code' render element for theme_element().
|
||||
*
|
||||
* @param array $element
|
||||
* An associative array containing the properties of the element.
|
||||
* Properties used: #title, #value, #description, #size, #maxlength,
|
||||
* #placeholder, #required, #attributes.
|
||||
*
|
||||
* @return array
|
||||
* The $element with prepared variables ready for theme_element().
|
||||
*/
|
||||
public static function preRenderWebformCodeMirror(array $element) {
|
||||
static::setAttributes($element, ['js-webform-codemirror', 'webform-codemirror', $element['#mode']]);
|
||||
$element['#attributes']['data-webform-codemirror-mode'] = static::getMode($element['#mode']);
|
||||
$element['#attached']['library'][] = 'webform/webform.element.codemirror.' . $element['#mode'];
|
||||
return $element;
|
||||
}
|
||||
|
||||
/**
|
||||
* Webform element validation handler for #type 'webform_codemirror'.
|
||||
*/
|
||||
public static function validateWebformCodeMirror(&$element, FormStateInterface $form_state, &$complete_form) {
|
||||
if ($errors = static::getErrors($element, $form_state, $complete_form)) {
|
||||
$build = [
|
||||
'title' => [
|
||||
'#markup' => t('%title is not valid.', ['%title' => (isset($element['#title']) ? $element['#title'] : t('YAML'))]),
|
||||
],
|
||||
'errors' => [
|
||||
'#theme' => 'item_list',
|
||||
'#items' => $errors,
|
||||
],
|
||||
];
|
||||
$form_state->setError($element, \Drupal::service('renderer')->render($build));
|
||||
}
|
||||
|
||||
if ($element['#mode'] == 'yaml' && (isset($element['#default_value']) && is_array($element['#default_value']))) {
|
||||
// Handle rare case where single array value is not parsed correctly.
|
||||
if (preg_match('/^- (.*?)\s*$/', $element['#value'], $match)) {
|
||||
$value = [$match[1]];
|
||||
}
|
||||
else {
|
||||
$value = $element['#value'] ? Yaml::decode($element['#value']) : [];
|
||||
}
|
||||
$form_state->setValueForElement($element, $value);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get validation errors.
|
||||
*/
|
||||
protected static function getErrors(&$element, FormStateInterface $form_state, &$complete_form) {
|
||||
if (!empty($element['#skip_validation'])) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
switch ($element['#mode']) {
|
||||
case 'html':
|
||||
// @see: http://stackoverflow.com/questions/3167074/which-function-in-php-validate-if-the-string-is-valid-html
|
||||
// @see: http://stackoverflow.com/questions/5030392/x-html-validator-in-php
|
||||
libxml_use_internal_errors(TRUE);
|
||||
if (simplexml_load_string('<fragment>' . $element['#value'] . '</fragment>')) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
$errors = libxml_get_errors();
|
||||
libxml_clear_errors();
|
||||
if (!$errors) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
$messages = [];
|
||||
foreach ($errors as $error) {
|
||||
$messages[] = $error->message;
|
||||
}
|
||||
return $messages;
|
||||
|
||||
case 'yaml':
|
||||
try {
|
||||
$value = trim($element['#value']);
|
||||
$data = Yaml::decode($value);
|
||||
if (!is_array($data) && $value) {
|
||||
throw new \Exception(t('YAML must contain an associative array of elements.'));
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
catch (\Exception $exception) {
|
||||
return [$exception->getMessage()];
|
||||
}
|
||||
|
||||
default:
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the CodeMirror mode for specified type.
|
||||
*
|
||||
* @param string $mode
|
||||
* Mode (text, html, or yaml).
|
||||
*
|
||||
* @return string
|
||||
* The CodeMirror mode (aka mime type).
|
||||
*/
|
||||
public static function getMode($mode) {
|
||||
return (isset(static::$modes[$mode])) ? static::$modes[$mode] : static::$modes['text'];
|
||||
}
|
||||
|
||||
}
|
||||
184
web/modules/contrib/webform/src/Element/WebformCompositeBase.php
Normal file
184
web/modules/contrib/webform/src/Element/WebformCompositeBase.php
Normal file
|
|
@ -0,0 +1,184 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\webform\Element;
|
||||
|
||||
use Drupal\Core\Form\FormStateInterface;
|
||||
use Drupal\Core\Render\Element\FormElement;
|
||||
use Drupal\Core\Render\Element\CompositeFormElementTrait;
|
||||
use Drupal\webform\Entity\WebformOptions as WebformOptionsEntity;
|
||||
|
||||
/**
|
||||
* Provides an base composite webform element.
|
||||
*/
|
||||
abstract class WebformCompositeBase extends FormElement {
|
||||
|
||||
use CompositeFormElementTrait;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getInfo() {
|
||||
$class = get_class($this);
|
||||
return [
|
||||
'#input' => TRUE,
|
||||
'#process' => [
|
||||
[$class, 'processWebformComposite'],
|
||||
[$class, 'processAjaxForm'],
|
||||
],
|
||||
'#pre_render' => [
|
||||
[$class, 'preRenderCompositeFormElement'],
|
||||
],
|
||||
'#theme' => str_replace('webform_', 'webform_composite_', $this->getPluginId()),
|
||||
'#theme_wrappers' => ['container'],
|
||||
'#title_display' => 'invisible',
|
||||
'#required' => FALSE,
|
||||
'#flexbox' => TRUE,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function valueCallback(&$element, $input, FormStateInterface $form_state) {
|
||||
$composite_elements = static::getCompositeElements();
|
||||
$default_value = [];
|
||||
foreach ($composite_elements as $composite_key => $composite_element) {
|
||||
if (isset($composite_element['#type']) && $composite_element['#type'] != 'label') {
|
||||
$default_value[$composite_key] = '';
|
||||
}
|
||||
}
|
||||
|
||||
if ($input === FALSE) {
|
||||
if (empty($element['#default_value']) || !is_array($element['#default_value'])) {
|
||||
$element['#default_value'] = [];
|
||||
}
|
||||
return $element['#default_value'] + $default_value;
|
||||
}
|
||||
return (is_array($input)) ? $input + $default_value : $default_value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a renderable array of webform elements.
|
||||
*
|
||||
* @return array
|
||||
* A renderable array of webform elements, containing the base properties
|
||||
* for the composite's webform elements.
|
||||
*/
|
||||
public static function getCompositeElements() {
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function preRenderCompositeFormElement($element) {
|
||||
$element = CompositeFormElementTrait::preRenderCompositeFormElement($element);
|
||||
|
||||
// Add class name to wrapper attributes.
|
||||
$class_name = str_replace('_', '-', $element['#type']);
|
||||
$element['#attributes']['class'][] = 'js-' . $class_name;
|
||||
$element['#attributes']['class'][] = $class_name;
|
||||
|
||||
return $element;
|
||||
}
|
||||
|
||||
/**
|
||||
* Processes a composite webform element.
|
||||
*/
|
||||
public static function processWebformComposite(&$element, FormStateInterface $form_state, &$complete_form) {
|
||||
if (isset($element['#initialize'])) {
|
||||
return $element;
|
||||
}
|
||||
|
||||
$element['#initialize'] = TRUE;
|
||||
$element['#tree'] = TRUE;
|
||||
$composite_elements = static::getCompositeElements();
|
||||
foreach ($composite_elements as $composite_key => &$composite_element) {
|
||||
// Transfer '#{composite_key}_{property}' from main element to composite
|
||||
// element.
|
||||
foreach ($element as $property_key => $property_value) {
|
||||
if (strpos($property_key, '#' . $composite_key . '__') === 0) {
|
||||
$composite_property_key = str_replace('#' . $composite_key . '__', '#', $property_key);
|
||||
$composite_element[$composite_property_key] = $property_value;
|
||||
}
|
||||
}
|
||||
|
||||
if (isset($element['#value'][$composite_key])) {
|
||||
$composite_element['#value'] = $element['#value'][$composite_key];
|
||||
}
|
||||
|
||||
// Always set #access which is used to hide/show the elements container.
|
||||
$composite_element += [
|
||||
'#access' => TRUE,
|
||||
];
|
||||
|
||||
// Never required hidden composite elements.
|
||||
if ($composite_element['#access'] == FALSE) {
|
||||
unset($composite_element['#required']);
|
||||
}
|
||||
|
||||
// Load options.
|
||||
if (isset($composite_element['#options'])) {
|
||||
$composite_element['#options'] = WebformOptionsEntity::getElementOptions($composite_element);
|
||||
}
|
||||
|
||||
// Handle #type specific customizations.
|
||||
if (isset($composite_element['#type'])) {
|
||||
switch ($composite_element['#type']) {
|
||||
case 'tel':
|
||||
// Add international phone library.
|
||||
// Add internation library and classes.
|
||||
if (!empty($composite_element['#international'])) {
|
||||
$composite_element['#attached']['library'][] = 'webform/webform.element.telephone';
|
||||
$composite_element['#attributes']['class'][] = 'js-webform-telephone-international';
|
||||
$composite_element['#attributes']['class'][] = 'webform-webform-telephone-international';
|
||||
}
|
||||
break;
|
||||
|
||||
case 'select':
|
||||
case 'webform_select_other':
|
||||
// Always include an empty option, even if the composite element
|
||||
// is not required.
|
||||
// @see https://api.drupal.org/api/drupal/core!lib!Drupal!Core!Render!Element!Select.php/class/Select/8.2.x
|
||||
// Use placeholder as empty option.
|
||||
if (!isset($composite_element['#empty_option'])) {
|
||||
if (isset($composite_element['#placeholder'])) {
|
||||
$composite_element['#empty_option'] = $composite_element['#placeholder'];
|
||||
}
|
||||
elseif (empty($composite_element['#required'])) {
|
||||
$composite_element['#empty_option'] = t('- None -');
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$element += $composite_elements;
|
||||
$element['#element_validate'] = [[get_called_class(), 'validateWebformComposite']];
|
||||
|
||||
if (!empty($element['#flexbox'])) {
|
||||
$element['#attached']['library'][] = 'webform/webform.element.flexbox';
|
||||
}
|
||||
|
||||
return $element;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates a composite element.
|
||||
*/
|
||||
public static function validateWebformComposite(&$element, FormStateInterface $form_state, &$complete_form) {
|
||||
$value = $element['#value'];
|
||||
|
||||
// Validate required composite elements.
|
||||
$composite_elements = static::getCompositeElements();
|
||||
foreach ($composite_elements as $composite_key => $composite_element) {
|
||||
if (!empty($element[$composite_key]['#required']) && $value[$composite_key] == '') {
|
||||
if (isset($element[$composite_key]['#title'])) {
|
||||
$form_state->setError($element[$composite_key], t('@name field is required.', ['@name' => $element[$composite_key]['#title']]));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
37
web/modules/contrib/webform/src/Element/WebformContact.php
Normal file
37
web/modules/contrib/webform/src/Element/WebformContact.php
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\webform\Element;
|
||||
|
||||
/**
|
||||
* Provides a webform element for a contact element.
|
||||
*
|
||||
* @FormElement("webform_contact")
|
||||
*/
|
||||
class WebformContact extends WebformAddress {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function getCompositeElements() {
|
||||
$elements = [];
|
||||
$elements['name'] = [
|
||||
'#type' => 'textfield',
|
||||
'#title' => t('Name'),
|
||||
];
|
||||
$elements['company'] = [
|
||||
'#type' => 'textfield',
|
||||
'#title' => t('Company'),
|
||||
];
|
||||
$elements['email'] = [
|
||||
'#type' => 'email',
|
||||
'#title' => t('Email'),
|
||||
];
|
||||
$elements['phone'] = [
|
||||
'#type' => 'tel',
|
||||
'#title' => t('Phone'),
|
||||
];
|
||||
$elements += parent::getCompositeElements();
|
||||
return $elements;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,68 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\webform\Element;
|
||||
|
||||
/**
|
||||
* Provides a webform element for a credit card element.
|
||||
*
|
||||
* @FormElement("webform_creditcard")
|
||||
*/
|
||||
class WebformCreditCard extends WebformCompositeBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function getCompositeElements() {
|
||||
$month_options = range(1, 12);
|
||||
$year_options = range(date('Y'), date('Y') + 10);
|
||||
|
||||
$elements = [];
|
||||
$elements['warning'] = [
|
||||
'#type' => 'webform_message',
|
||||
'#message_type' => 'warning',
|
||||
'#message_message' => t('The credit card element is experimental and insecure because it stores submitted information as plain text.'),
|
||||
];
|
||||
$elements['name'] = [
|
||||
'#type' => 'textfield',
|
||||
'#title' => t("Name on Card"),
|
||||
];
|
||||
$elements['type'] = [
|
||||
'#type' => 'select',
|
||||
'#title' => t('Type of Card'),
|
||||
'#options' => 'creditcard_codes',
|
||||
];
|
||||
$elements['number'] = [
|
||||
'#type' => 'webform_creditcard_number',
|
||||
'#title' => t('Card Number'),
|
||||
];
|
||||
$elements['civ'] = [
|
||||
'#type' => 'number',
|
||||
'#title' => t('CIV Number'),
|
||||
'#min' => 1,
|
||||
'#size' => 4,
|
||||
'#maxlength' => 4,
|
||||
'#test' => [111, 222, 333],
|
||||
];
|
||||
$elements['expiration'] = [
|
||||
'#type' => 'label',
|
||||
'#title' => t('Expiration Date'),
|
||||
];
|
||||
$elements['expiration_month'] = [
|
||||
'#title' => t('Expiration Month'),
|
||||
'#title_display' => 'invisible',
|
||||
'#type' => 'select',
|
||||
'#options' => array_combine($month_options, $month_options),
|
||||
'#prefix' => '<div class="container-inline clearfix">',
|
||||
];
|
||||
$elements['expiration_year'] = [
|
||||
'#title' => t('Expiration Year'),
|
||||
'#title_display' => 'invisible',
|
||||
'#type' => 'select',
|
||||
'#options' => array_combine($year_options, $year_options),
|
||||
'#suffix' => '</div>',
|
||||
];
|
||||
|
||||
return $elements;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,122 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\webform\Element;
|
||||
|
||||
use Drupal\Core\Render\Element;
|
||||
use Drupal\Core\Render\Element\FormElement;
|
||||
use Drupal\Core\Form\FormStateInterface;
|
||||
|
||||
/**
|
||||
* Provides a webform element for entering a credit card number.
|
||||
*
|
||||
* @FormElement("webform_creditcard_number")
|
||||
*/
|
||||
class WebformCreditCardNumber extends FormElement {
|
||||
|
||||
/**
|
||||
* Defines the max length for an credit card number.
|
||||
*/
|
||||
const CREDITCARD_MAX_LENGTH = 16;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getInfo() {
|
||||
$class = get_class($this);
|
||||
return [
|
||||
'#input' => TRUE,
|
||||
'#size' => self::CREDITCARD_MAX_LENGTH,
|
||||
'#maxlength' => self::CREDITCARD_MAX_LENGTH,
|
||||
'#autocomplete_route_name' => FALSE,
|
||||
'#process' => [
|
||||
[$class, 'processAutocomplete'],
|
||||
[$class, 'processAjaxForm'],
|
||||
[$class, 'processPattern'],
|
||||
],
|
||||
'#element_validate' => [
|
||||
[$class, 'validateWebformCreditCardNumber'],
|
||||
],
|
||||
'#pre_render' => [
|
||||
[$class, 'preRenderWebformCreditCardNumber'],
|
||||
],
|
||||
'#theme' => 'input__creditcard_number',
|
||||
'#theme_wrappers' => ['form_element'],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Webform element validation handler for #type 'creditcard_number'.
|
||||
*/
|
||||
public static function validateWebformCreditCardNumber(&$element, FormStateInterface $form_state, &$complete_form) {
|
||||
$value = trim($element['#value']);
|
||||
$form_state->setValueForElement($element, $value);
|
||||
|
||||
if ($value !== '' && !self::validCreditCardNumber($value)) {
|
||||
$form_state->setError($element, t('The credit card number is not valid.'));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Validation rule for credit card number.
|
||||
*
|
||||
* Luhn algorithm number checker - (c) 2005-2008 shaman - www.planzero.org
|
||||
* This code has been released into the public domain, however please
|
||||
* give credit to the original author where possible.
|
||||
*
|
||||
* @param string $number
|
||||
* A credit card number.
|
||||
*
|
||||
* @return bool
|
||||
* TRUE is credit card number is valid.
|
||||
*
|
||||
* @see: http://stackoverflow.com/questions/174730/what-is-the-best-way-to-validate-a-credit-card-in-php
|
||||
*/
|
||||
public static function validCreditCardNumber($number) {
|
||||
// If number is not 15 or 16 digits return FALSE.
|
||||
if (!preg_match('/^\d{15,16}$/', $number)) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// Set the string length and parity.
|
||||
$number_length = strlen($number);
|
||||
$parity = $number_length % 2;
|
||||
|
||||
// Loop through each digit and do the maths.
|
||||
$total = 0;
|
||||
for ($i = 0; $i < $number_length; $i++) {
|
||||
$digit = $number[$i];
|
||||
// Multiply alternate digits by two.
|
||||
if ($i % 2 == $parity) {
|
||||
$digit *= 2;
|
||||
// If the sum is two digits, add them together (in effect).
|
||||
if ($digit > 9) {
|
||||
$digit -= 9;
|
||||
}
|
||||
}
|
||||
// Total up the digits.
|
||||
$total += $digit;
|
||||
}
|
||||
|
||||
// If the total mod 10 equals 0, the number is valid.
|
||||
return ($total % 10 == 0) ? TRUE : FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepares a #type 'creditcard_number' render element for theme_element().
|
||||
*
|
||||
* @param array $element
|
||||
* An associative array containing the properties of the element.
|
||||
* Properties used: #title, #value, #description, #size, #maxlength,
|
||||
* #placeholder, #required, #attributes.
|
||||
*
|
||||
* @return array
|
||||
* The $element with prepared variables ready for theme_element().
|
||||
*/
|
||||
public static function preRenderWebformCreditCardNumber(array $element) {
|
||||
$element['#attributes']['type'] = 'text';
|
||||
Element::setAttributes($element, ['id', 'name', 'value', 'size', 'maxlength', 'placeholder']);
|
||||
static::setAttributes($element, ['form-textfield', 'form-creditcard-number']);
|
||||
return $element;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\webform\Element;
|
||||
|
||||
/**
|
||||
* Provides a webform element for an 'document_file' element.
|
||||
*
|
||||
* @FormElement("webform_document_file")
|
||||
*/
|
||||
class WebformDocumentFile extends WebformManagedFileBase {
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,197 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\webform\Element;
|
||||
|
||||
use Drupal\Component\Utility\Unicode;
|
||||
use Drupal\Core\Form\FormStateInterface;
|
||||
use Drupal\Core\Render\Element\FormElement;
|
||||
use Drupal\Core\Serialization\Yaml;
|
||||
use Drupal\webform\Utility\WebformYaml;
|
||||
|
||||
/**
|
||||
* Provides a webform element for element attributes.
|
||||
*
|
||||
* @FormElement("webform_element_attributes")
|
||||
*/
|
||||
class WebformElementAttributes extends FormElement {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getInfo() {
|
||||
$class = get_class($this);
|
||||
return [
|
||||
'#input' => TRUE,
|
||||
'#process' => [
|
||||
[$class, 'processWebformElementAttributes'],
|
||||
],
|
||||
'#theme_wrappers' => ['container'],
|
||||
'#classes' => '',
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function valueCallback(&$element, $input, FormStateInterface $form_state) {
|
||||
$element += ['#default_value' => []];
|
||||
$element['#default_value'] += [
|
||||
'class' => [],
|
||||
'style' => '',
|
||||
];
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Processes element attributes.
|
||||
*/
|
||||
public static function processWebformElementAttributes(&$element, FormStateInterface $form_state, &$complete_form) {
|
||||
$element['#tree'] = TRUE;
|
||||
|
||||
// Determine what type of HTML element the attributes are being applied to.
|
||||
$type = t('element');
|
||||
$types = [preg_quote(t('webform')), preg_quote(t('link')), preg_quote(t('button'))];
|
||||
if (preg_match('/\b(' . implode('|', $types) . ')\b/i', $element['#title'], $match)) {
|
||||
$type = $match[1];
|
||||
}
|
||||
|
||||
$t_args = [
|
||||
'@title' => $element['#title'],
|
||||
'@type' => Unicode::strtolower($type),
|
||||
];
|
||||
|
||||
// Class.
|
||||
$element['#classes'] = trim($element['#classes']);
|
||||
if ($element['#classes']) {
|
||||
$classes = preg_split('/\r?\n/', $element['#classes']);
|
||||
$element['class'] = [
|
||||
'#type' => 'webform_select_other',
|
||||
'#title' => t('@title CSS classes', $t_args),
|
||||
'#description' => t("Apply classes to the @type. Select 'custom...' to enter custom classes.", $t_args),
|
||||
'#multiple' => TRUE,
|
||||
'#options' => [WebformSelectOther::OTHER_OPTION => t('custom...')] + array_combine($classes, $classes),
|
||||
'#other__option_delimiter' => ' ',
|
||||
'#attributes' => [
|
||||
'class' => [
|
||||
'js-webform-select2',
|
||||
'webform-select2',
|
||||
'js-' . $element['#id'] . '-attributes-style',
|
||||
],
|
||||
],
|
||||
'#attached' => ['library' => ['webform/webform.element.select2']],
|
||||
'#default_value' => $element['#default_value']['class'],
|
||||
];
|
||||
|
||||
// ISSUE:
|
||||
// Nested element with #element_validate callback that alter an
|
||||
// element's value can break the returned value.
|
||||
//
|
||||
// WORKAROUND:
|
||||
// Manually process the 'webform_select_other' element.
|
||||
WebformSelectOther::valueCallback($element['class'], FALSE, $form_state);
|
||||
WebformSelectOther::processWebformOther($element['class'], $form_state, $complete_form);
|
||||
|
||||
$element['class']['#type'] = 'item';
|
||||
unset($element['class']['#element_validate']);
|
||||
}
|
||||
else {
|
||||
$element['class'] = [
|
||||
'#type' => 'textfield',
|
||||
'#title' => t('@title CSS classes', $t_args),
|
||||
'#description' => t("Apply classes to the @type.", $t_args),
|
||||
'#default_value' => implode(' ', $element['#default_value']['class']),
|
||||
];
|
||||
}
|
||||
|
||||
// Custom options.
|
||||
$element['custom'] = [
|
||||
'#type' => 'texfield',
|
||||
'#placeholder' => t('Enter custom classes...'),
|
||||
'#states' => [
|
||||
'visible' => [
|
||||
'select.js-' . $element['#id'] . '-attributes-style' => ['value' => '_custom_'],
|
||||
],
|
||||
],
|
||||
'#error_no_message' => TRUE,
|
||||
'#default_value' => '',
|
||||
];
|
||||
|
||||
// Style.
|
||||
$element['style'] = [
|
||||
'#type' => 'textfield',
|
||||
'#title' => t('@title CSS style', $t_args),
|
||||
'#description' => t('Apply custom styles to the @type.', $t_args),
|
||||
'#default_value' => $element['#default_value']['style'],
|
||||
];
|
||||
|
||||
// Attributes.
|
||||
$attributes = $element['#default_value'];
|
||||
unset($attributes['class'], $attributes['style']);
|
||||
$element['attributes'] = [
|
||||
'#type' => 'webform_codemirror',
|
||||
'#mode' => 'yaml',
|
||||
'#title' => t('@title custom attributes (YAML)', $t_args),
|
||||
'#description' => t('Enter additional attributes to be added the @type.', $t_args),
|
||||
'#attributes__access' => (!\Drupal::moduleHandler()->moduleExists('webform_ui') || \Drupal::currentUser()->hasPermission('edit webform source')),
|
||||
'#default_value' => WebformYaml::tidy(Yaml::encode($attributes)),
|
||||
];
|
||||
|
||||
// Apply custom properties. Typically used for descriptions.
|
||||
foreach ($element as $key => $value) {
|
||||
if (strpos($key, '__') !== FALSE) {
|
||||
list($element_key, $property_key) = explode('__', ltrim($key, '#'));
|
||||
$element[$element_key]["#$property_key"] = $value;
|
||||
}
|
||||
}
|
||||
|
||||
// Set validation.
|
||||
if (isset($element['#element_validate'])) {
|
||||
$element['#element_validate'] = array_merge([[get_called_class(), 'validateWebformElementAttributes']], $element['#element_validate']);
|
||||
}
|
||||
else {
|
||||
$element['#element_validate'] = [[get_called_class(), 'validateWebformElementAttributes']];
|
||||
}
|
||||
|
||||
return $element;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates element attributes.
|
||||
*/
|
||||
public static function validateWebformElementAttributes(&$element, FormStateInterface $form_state, &$complete_form) {
|
||||
$values = $element['#value'];
|
||||
|
||||
$attributes = [];
|
||||
|
||||
if ($values['class']) {
|
||||
if (isset($element['class']['select'])) {
|
||||
$class = $element['class']['select']['#value'];
|
||||
$class_other = $element['class']['other']['#value'];
|
||||
if (isset($class[WebformSelectOther::OTHER_OPTION])) {
|
||||
unset($class[WebformSelectOther::OTHER_OPTION]);
|
||||
$class[$class_other] = $class_other;
|
||||
}
|
||||
if ($class) {
|
||||
$attributes['class'] = array_values($class);
|
||||
}
|
||||
}
|
||||
else {
|
||||
$attributes['class'] = [$values['class']];
|
||||
}
|
||||
}
|
||||
|
||||
if ($values['style']) {
|
||||
$attributes['style'] = $values['style'];
|
||||
}
|
||||
|
||||
if (!empty($values['attributes'])) {
|
||||
$attributes += Yaml::decode($values['attributes']);
|
||||
}
|
||||
|
||||
$form_state->setValueForElement($element['class'], NULL);
|
||||
$form_state->setValueForElement($element['style'], NULL);
|
||||
$form_state->setValueForElement($element['attributes'], NULL);
|
||||
$form_state->setValueForElement($element, $attributes);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,137 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\webform\Element;
|
||||
|
||||
use Drupal\Core\Form\FormStateInterface;
|
||||
use Drupal\Core\Render\Element\FormElement;
|
||||
|
||||
/**
|
||||
* Provides a webform element for element multiple property.
|
||||
*
|
||||
* This element displays the #multiple property so that it looks like
|
||||
* the cardinality setting included in the Field API.
|
||||
*
|
||||
* @FormElement("webform_element_multiple")
|
||||
*
|
||||
* @see \Drupal\field_ui\Form\FieldStorageConfigEditForm::form
|
||||
*/
|
||||
class WebformElementMultiple extends FormElement {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getInfo() {
|
||||
$class = get_class($this);
|
||||
return [
|
||||
'#input' => TRUE,
|
||||
'#min' => 1,
|
||||
'#process' => [
|
||||
[$class, 'processWebformElementMultiple'],
|
||||
],
|
||||
'#theme_wrappers' => ['form_element'],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function valueCallback(&$element, $input, FormStateInterface $form_state) {
|
||||
if ($input === FALSE) {
|
||||
if (empty($element['#default_value'])) {
|
||||
return 1;
|
||||
}
|
||||
elseif ($element['#default_value'] === TRUE) {
|
||||
return WebformMultiple::CARDINALITY_UNLIMITED;
|
||||
}
|
||||
else {
|
||||
return $element['#default_value'];
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Processes element multiple.
|
||||
*/
|
||||
public static function processWebformElementMultiple(&$element, FormStateInterface $form_state, &$complete_form) {
|
||||
$cardinality = $element['#value'];
|
||||
|
||||
$element['#tree'] = TRUE;
|
||||
|
||||
$element['container'] = [
|
||||
'#type' => 'container',
|
||||
'#attributes' => ['class' => [
|
||||
'container-inline',
|
||||
]],
|
||||
];
|
||||
|
||||
$element['container']['cardinality'] = [
|
||||
'#type' => 'select',
|
||||
'#title' => t('Allowed number of values'),
|
||||
'#title_display' => 'invisible',
|
||||
'#options' => [
|
||||
'number' => t('Limited'),
|
||||
WebformMultiple::CARDINALITY_UNLIMITED => t('Unlimited'),
|
||||
],
|
||||
'#default_value' => ($cardinality == WebformMultiple::CARDINALITY_UNLIMITED) ? WebformMultiple::CARDINALITY_UNLIMITED : 'number',
|
||||
];
|
||||
$element['container']['cardinality_number'] = [
|
||||
'#type' => 'number',
|
||||
'#default_value' => $cardinality != WebformMultiple::CARDINALITY_UNLIMITED ? $cardinality : $element['#min'],
|
||||
'#min' => $element['#min'],
|
||||
'#title' => t('Limit'),
|
||||
'#title_display' => 'invisible',
|
||||
'#size' => 2,
|
||||
'#states' => [
|
||||
'visible' => [
|
||||
':input[data-drupal-selector="edit-' . implode('-', $element['#parents']) . '-container-cardinality"]' => ['value' => 'number'],
|
||||
],
|
||||
],
|
||||
];
|
||||
|
||||
// Set disabled
|
||||
if (!empty($element['#disabled'])) {
|
||||
$element['container']['cardinality']['#disabled'] = TRUE;
|
||||
$element['container']['cardinality_number']['#disabled'] = TRUE;
|
||||
}
|
||||
|
||||
// Set validation.
|
||||
if (isset($element['#element_validate'])) {
|
||||
$element['#element_validate'] = array_merge([[get_called_class(), 'validateWebformElementMultiple']], $element['#element_validate']);
|
||||
}
|
||||
else {
|
||||
$element['#element_validate'] = [[get_called_class(), 'validateWebformElementMultiple']];
|
||||
}
|
||||
|
||||
return $element;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates element multiple.
|
||||
*/
|
||||
public static function validateWebformElementMultiple(&$element, FormStateInterface $form_state, &$complete_form) {
|
||||
if (!empty($element['#disabled'])) {
|
||||
$multiple = $element['#default_value'];
|
||||
}
|
||||
else {
|
||||
$cardinality = $element['#value']['container']['cardinality'];
|
||||
$cardinality_number = (int) $element['#value']['container']['cardinality_number'];
|
||||
|
||||
if ($cardinality == WebformMultiple::CARDINALITY_UNLIMITED) {
|
||||
$multiple = TRUE;
|
||||
}
|
||||
elseif ($cardinality_number === 1) {
|
||||
$multiple = FALSE;
|
||||
}
|
||||
else {
|
||||
$multiple = $cardinality_number;
|
||||
}
|
||||
}
|
||||
|
||||
$form_state->setValueForElement($element['container']['cardinality'], NULL);
|
||||
$form_state->setValueForElement($element['container']['cardinality_number'], NULL);
|
||||
$form_state->setValueForElement($element, $multiple);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,179 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\webform\Element;
|
||||
|
||||
use Drupal\Component\Utility\NestedArray;
|
||||
use Drupal\Core\Serialization\Yaml;
|
||||
use Drupal\Core\Form\FormStateInterface;
|
||||
use Drupal\Core\Render\Element\FormElement;
|
||||
use Drupal\Core\Url;
|
||||
use Drupal\webform\Entity\WebformOptions as WebformOptionsEntity;
|
||||
|
||||
/**
|
||||
* Provides a webform element for managing webform element options.
|
||||
*
|
||||
* This element is used by select, radios, checkboxes, and likert elements.
|
||||
*
|
||||
* @FormElement("webform_element_options")
|
||||
*/
|
||||
class WebformElementOptions extends FormElement {
|
||||
|
||||
const CUSTOM_OPTION = '';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getInfo() {
|
||||
$class = get_class($this);
|
||||
return [
|
||||
'#input' => TRUE,
|
||||
'#likert' => FALSE,
|
||||
'#process' => [
|
||||
[$class, 'processWebformElementOptions'],
|
||||
[$class, 'processAjaxForm'],
|
||||
],
|
||||
'#theme_wrappers' => ['form_element'],
|
||||
'#custom__type' => 'webform_options',
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function valueCallback(&$element, $input, FormStateInterface $form_state) {
|
||||
if ($input === FALSE) {
|
||||
if (isset($element['#default_value'])) {
|
||||
if (is_string($element['#default_value'])) {
|
||||
return (WebformOptionsEntity::load($element['#default_value'])) ? $element['#default_value'] : [];
|
||||
}
|
||||
else {
|
||||
return $element['#default_value'];
|
||||
}
|
||||
}
|
||||
else {
|
||||
return [];
|
||||
}
|
||||
}
|
||||
elseif (!empty($input['options'])) {
|
||||
return $input['options'];
|
||||
}
|
||||
elseif (isset($input['custom']['options'])) {
|
||||
return $input['custom']['options'];
|
||||
}
|
||||
else {
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Processes a webform element options element.
|
||||
*/
|
||||
public static function processWebformElementOptions(&$element, FormStateInterface $form_state, &$complete_form) {
|
||||
$element['#tree'] = TRUE;
|
||||
|
||||
// Predefined options.
|
||||
// @see (/admin/structure/webform/settings/options/manage)
|
||||
$options = [];
|
||||
$webform_options = WebformOptionsEntity::loadMultiple();
|
||||
foreach ($webform_options as $id => $webform_option) {
|
||||
// Filter likert options for answers to the likert element.
|
||||
if ($element['#likert'] && strpos($id, 'likert_') !== 0) {
|
||||
continue;
|
||||
}
|
||||
$options[$id] = $webform_option->label();
|
||||
}
|
||||
asort($options);
|
||||
|
||||
$t_args = [
|
||||
'@type' => ($element['#likert']) ? t('answers') : t('options'),
|
||||
':href' => Url::fromRoute('entity.webform_options.collection')->toString(),
|
||||
];
|
||||
|
||||
// Select options.
|
||||
$element['options'] = [
|
||||
'#type' => 'select',
|
||||
'#description' => t('Please select <a href=":href">predefined @type</a> or enter custom @type.', $t_args),
|
||||
'#options' => [
|
||||
self::CUSTOM_OPTION => t('Custom...'),
|
||||
] + $options,
|
||||
'#attributes' => [
|
||||
'class' => ['js-' . $element['#id'] . '-options'],
|
||||
],
|
||||
'#error_no_message' => TRUE,
|
||||
'#default_value' => (isset($element['#default_value']) && !is_array($element['#default_value'])) ? $element['#default_value'] : '',
|
||||
];
|
||||
|
||||
// Custom options.
|
||||
if ($element['#custom__type'] === 'webform_multiple') {
|
||||
$element['custom'] = [
|
||||
'#type' => 'webform_multiple',
|
||||
'#title' => $element['#title'],
|
||||
'#title_display' => 'invisible',
|
||||
'#states' => [
|
||||
'visible' => [
|
||||
'select.js-' . $element['#id'] . '-options' => ['value' => ''],
|
||||
],
|
||||
],
|
||||
'#error_no_message' => TRUE,
|
||||
'#default_value' => (isset($element['#default_value']) && !is_string($element['#default_value'])) ? $element['#default_value'] : [],
|
||||
];
|
||||
}
|
||||
else {
|
||||
$element['custom'] = [
|
||||
'#type' => 'webform_options',
|
||||
'#title' => $element['#title'],
|
||||
'#title_display' => 'invisible',
|
||||
'#label' => ($element['#likert']) ? t('answer') : t('option'),
|
||||
'#labels' => ($element['#likert']) ? t('answers') : t('options'),
|
||||
'#states' => [
|
||||
'visible' => [
|
||||
'select.js-' . $element['#id'] . '-options' => ['value' => ''],
|
||||
],
|
||||
],
|
||||
'#error_no_message' => TRUE,
|
||||
'#default_value' => (isset($element['#default_value']) && !is_string($element['#default_value'])) ? $element['#default_value'] : [],
|
||||
];
|
||||
}
|
||||
|
||||
$element['#element_validate'] = [[get_called_class(), 'validateWebformElementOptions']];
|
||||
|
||||
return $element;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates a webform element options element.
|
||||
*/
|
||||
public static function validateWebformElementOptions(&$element, FormStateInterface $form_state, &$complete_form) {
|
||||
$options_value = NestedArray::getValue($form_state->getValues(), $element['options']['#parents']);
|
||||
$custom_value = NestedArray::getValue($form_state->getValues(), $element['custom']['#parents']);
|
||||
|
||||
$value = $options_value;
|
||||
if ($options_value == self::CUSTOM_OPTION) {
|
||||
try {
|
||||
$value = (is_string($custom_value)) ? Yaml::decode($custom_value) : $custom_value;
|
||||
}
|
||||
catch (\Exception $exception) {
|
||||
// Do nothing since the 'webform_codemirror' element will have already
|
||||
// captured the validation error.
|
||||
}
|
||||
}
|
||||
|
||||
$has_access = (!isset($element['#access']) || $element['#access'] === TRUE);
|
||||
if ($element['#required'] && empty($value) && $has_access) {
|
||||
if (isset($element['#required_error'])) {
|
||||
$form_state->setError($element, $element['#required_error']);
|
||||
}
|
||||
elseif (isset($element['#title'])) {
|
||||
$form_state->setError($element, t('@name field is required.', ['@name' => $element['#title']]));
|
||||
}
|
||||
else {
|
||||
$form_state->setError($element);
|
||||
}
|
||||
}
|
||||
|
||||
$form_state->setValueForElement($element['options'], NULL);
|
||||
$form_state->setValueForElement($element['custom'], NULL);
|
||||
$form_state->setValueForElement($element, $value);
|
||||
}
|
||||
|
||||
}
|
||||
720
web/modules/contrib/webform/src/Element/WebformElementStates.php
Normal file
720
web/modules/contrib/webform/src/Element/WebformElementStates.php
Normal file
|
|
@ -0,0 +1,720 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\webform\Element;
|
||||
|
||||
use Drupal\Component\Utility\NestedArray;
|
||||
use Drupal\Core\Serialization\Yaml;
|
||||
use Drupal\Component\Utility\Unicode;
|
||||
use Drupal\Core\Render\Element\FormElement;
|
||||
use Drupal\Core\Form\FormStateInterface;
|
||||
use Drupal\webform\Utility\WebformArrayHelper;
|
||||
use Drupal\webform\Utility\WebformYaml;
|
||||
|
||||
/**
|
||||
* Provides a webform element to edit an element's #states.
|
||||
*
|
||||
* @FormElement("webform_element_states")
|
||||
*/
|
||||
class WebformElementStates extends FormElement {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getInfo() {
|
||||
$class = get_class($this);
|
||||
return [
|
||||
'#input' => TRUE,
|
||||
'#selector_options' => [],
|
||||
'#empty_states' => 3,
|
||||
'#process' => [
|
||||
[$class, 'processWebformStates'],
|
||||
],
|
||||
'#theme_wrappers' => ['form_element'],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function valueCallback(&$element, $input, FormStateInterface $form_state) {
|
||||
if ($input === FALSE) {
|
||||
if (isset($element['#default_value'])) {
|
||||
if (is_string($element['#default_value'])) {
|
||||
$default_value = Yaml::decode($element['#default_value']);
|
||||
}
|
||||
else {
|
||||
$default_value = $element['#default_value'] ?: [];
|
||||
}
|
||||
return self::convertFormApiStatesToStatesArray($default_value);
|
||||
}
|
||||
else {
|
||||
return [];
|
||||
}
|
||||
}
|
||||
elseif (is_array($input) && isset($input['states'])) {
|
||||
return (is_string($input['states'])) ? Yaml::decode($input['states']) : self::convertFormValuesToStatesArray($input['states']);
|
||||
}
|
||||
else {
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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\WebformElementBase::form.
|
||||
$element += [
|
||||
'#state_options' => [
|
||||
'enabled' => t('Enabled'),
|
||||
'disabled' => t('Disabled'),
|
||||
'required' => t('Required'),
|
||||
'optional' => t('Optional'),
|
||||
'visible' => t('Visible'),
|
||||
'invisible' => t('Invisible'),
|
||||
'checked' => t('Checked'),
|
||||
'unchecked' => t('Unchecked'),
|
||||
'expanded' => t('Expanded'),
|
||||
'collapsed' => t('Collapsed'),
|
||||
],
|
||||
'#trigger_options' => [
|
||||
'empty' => t('Empty'),
|
||||
'filled' => t('Filled'),
|
||||
'checked' => t('Checked'),
|
||||
'unchecked' => t('Unchecked'),
|
||||
'expanded' => t('Expanded'),
|
||||
'collapsed' => t('Collapsed'),
|
||||
'value' => t('Value is'),
|
||||
],
|
||||
];
|
||||
|
||||
$element['#tree'] = TRUE;
|
||||
|
||||
// Add validate callback that extracts the associative array of states.
|
||||
$element['#element_validate'] = [[get_called_class(), 'validateWebformElementStates']];
|
||||
|
||||
// For customized #states display a CodeMirror YAML editor.
|
||||
if ($warning_message = self::isDefaultValueCustomizedFormApiStates($element)) {
|
||||
$warning_message .= ' ' . t('Form API #states must be manually entered.');
|
||||
$element['messages'] = [
|
||||
'#type' => 'webform_message',
|
||||
'#message_type' => 'warning',
|
||||
'#message_message' => $warning_message,
|
||||
];
|
||||
$element['states'] = [
|
||||
'#type' => 'webform_codemirror',
|
||||
'#mode' => 'yaml',
|
||||
'#default_value' => WebformYaml::tidy(Yaml::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']),
|
||||
];
|
||||
return $element;
|
||||
}
|
||||
|
||||
$table_id = implode('_', $element['#parents']) . '_table';
|
||||
|
||||
// Store the number of rows.
|
||||
$storage_key = self::getStorageKey($element, 'number_of_rows');
|
||||
if ($form_state->get($storage_key) === NULL) {
|
||||
if (empty($element['#default_value']) || !is_array($element['#default_value'])) {
|
||||
$number_of_rows = 2;
|
||||
}
|
||||
else {
|
||||
$number_of_rows = count($element['#default_value']);
|
||||
}
|
||||
$form_state->set($storage_key, $number_of_rows);
|
||||
}
|
||||
$number_of_rows = $form_state->get($storage_key);
|
||||
|
||||
// DEBUG: Disable AJAX callback by commenting out the below callback and
|
||||
// wrapper.
|
||||
$ajax_settings = [
|
||||
'callback' => [get_called_class(), 'ajaxCallback'],
|
||||
'wrapper' => $table_id,
|
||||
];
|
||||
|
||||
// Build header.
|
||||
$header = [
|
||||
['data' => t('State'), 'width' => '20%'],
|
||||
['data' => t('Element/Selector'), 'width' => '45%'],
|
||||
['data' => t('Trigger'), 'width' => '20%'],
|
||||
['data' => t('Value'), 'width' => '10%'],
|
||||
['data' => ''],
|
||||
];
|
||||
|
||||
// Get states and number of rows.
|
||||
if (($form_state->isRebuilding())) {
|
||||
$states = $element['#value'];
|
||||
}
|
||||
else {
|
||||
$states = (isset($element['#default_value'])) ? self::convertFormApiStatesToStatesArray($element['#default_value']) : [];
|
||||
}
|
||||
|
||||
// Build state and conditions rows.
|
||||
$row_index = 0;
|
||||
$rows = [];
|
||||
foreach ($states as $state_settings) {
|
||||
$rows[$row_index] = self::buildStateRow($element, $state_settings, $table_id, $row_index, $ajax_settings);
|
||||
$row_index++;
|
||||
foreach ($state_settings['conditions'] as $condition) {
|
||||
$rows[$row_index] = self::buildConditionRow($element, $condition, $table_id, $row_index, $ajax_settings);
|
||||
$row_index++;
|
||||
}
|
||||
}
|
||||
|
||||
// Generator empty state with conditions rows.
|
||||
if ($row_index < $number_of_rows) {
|
||||
$rows[$row_index] = self::buildStateRow($element, [], $table_id, $row_index, $ajax_settings);;
|
||||
$row_index++;
|
||||
while ($row_index < $number_of_rows) {
|
||||
$rows[$row_index] = self::buildConditionRow($element, [], $table_id, $row_index, $ajax_settings);
|
||||
$row_index++;
|
||||
}
|
||||
}
|
||||
|
||||
// Build table.
|
||||
$element['states'] = [
|
||||
'#prefix' => '<div id="' . $table_id . '" class="webform-states-table">',
|
||||
'#suffix' => '</div>',
|
||||
'#type' => 'table',
|
||||
'#header' => $header,
|
||||
] + $rows;
|
||||
|
||||
// Build add state action.
|
||||
$element['add'] = [
|
||||
'#type' => 'submit',
|
||||
'#value' => t('Add another state'),
|
||||
'#limit_validation_errors' => [],
|
||||
'#submit' => [[get_called_class(), 'addStateSubmit']],
|
||||
'#ajax' => $ajax_settings,
|
||||
'#name' => $table_id . '_add',
|
||||
];
|
||||
|
||||
$element['#attached']['library'][] = 'webform/webform.element.states';
|
||||
$element['#attached']['library'][] = 'webform/webform.element.select2';
|
||||
|
||||
return $element;
|
||||
}
|
||||
|
||||
/**
|
||||
* Build state row.
|
||||
*
|
||||
* @param array $element
|
||||
* The webform element.
|
||||
* @param array $state
|
||||
* The state.
|
||||
* @param string $table_id
|
||||
* The element's table id.
|
||||
* @param int $row_index
|
||||
* The row index.
|
||||
* @param array $ajax_settings
|
||||
* An array containing AJAX callback settings.
|
||||
*
|
||||
* @return array
|
||||
* A render array containing a state table row.
|
||||
*/
|
||||
protected static function buildStateRow(array $element, array $state, $table_id, $row_index, array $ajax_settings) {
|
||||
$state += ['state' => '', 'operator' => 'and'];
|
||||
$row = [
|
||||
'#attributes' => [
|
||||
'class' => ['webform-states-table--state'],
|
||||
],
|
||||
];
|
||||
$row['state'] = [
|
||||
'#type' => 'select',
|
||||
'#options' => $element['#state_options'],
|
||||
'#default_value' => $state['state'],
|
||||
'#empty_option' => '',
|
||||
'#empty_value' => '',
|
||||
'#attributes' => ['class' => ['js-webform-select2', 'webform-select2']],
|
||||
];
|
||||
$row['operator'] = [
|
||||
'#type' => 'select',
|
||||
'#options' => [
|
||||
'and' => t('All'),
|
||||
'or' => t('Any'),
|
||||
],
|
||||
'#default_value' => $state['operator'],
|
||||
'#field_prefix' => t('if'),
|
||||
'#field_suffix' => t('of the following is met:'),
|
||||
'#wrapper_attributes' => ['colspan' => 3, 'align' => 'left'],
|
||||
];
|
||||
$row['operations'] = self::buildOperations($table_id, $row_index, $ajax_settings);
|
||||
return $row;
|
||||
}
|
||||
|
||||
/**
|
||||
* Build condition row.
|
||||
*
|
||||
* @param array $element
|
||||
* The webform element.
|
||||
* @param array $condition
|
||||
* The condition.
|
||||
* @param string $table_id
|
||||
* The element's table id.
|
||||
* @param int $row_index
|
||||
* The row index.
|
||||
* @param array $ajax_settings
|
||||
* An array containing AJAX callback settings.
|
||||
*
|
||||
* @return array
|
||||
* A render array containing a condition table row.
|
||||
*/
|
||||
protected static function buildConditionRow(array $element, array $condition, $table_id, $row_index, array $ajax_settings) {
|
||||
$condition += ['selector' => '', 'trigger' => '', 'value' => ''];
|
||||
|
||||
$element_name = $element['#name'];
|
||||
$trigger_selector = ":input[name=\"{$element_name}[states][{$row_index}][trigger]\"]";
|
||||
|
||||
$row = [
|
||||
'#attributes' => [
|
||||
'class' => ['webform-states-table--condition'],
|
||||
],
|
||||
];
|
||||
$row['state'] = [];
|
||||
$row['selector'] = [
|
||||
'#type' => 'webform_select_other',
|
||||
'#options' => $element['#selector_options'],
|
||||
'#default_value' => $condition['selector'],
|
||||
'#empty_option' => '',
|
||||
'#empty_value' => '',
|
||||
'#attributes' => ['class' => ['js-webform-select2', 'webform-select2']],
|
||||
];
|
||||
$row['trigger'] = [
|
||||
'#type' => 'select',
|
||||
'#options' => $element['#trigger_options'],
|
||||
'#default_value' => $condition['trigger'],
|
||||
'#empty_option' => '',
|
||||
'#empty_value' => '',
|
||||
'#attributes' => ['class' => ['js-webform-select2', 'webform-select2']],
|
||||
];
|
||||
$row['value'] = [
|
||||
'#type' => 'textfield',
|
||||
'#title' => t('Value'),
|
||||
'#title_display' => 'invisible',
|
||||
'#size' => 25,
|
||||
'#default_value' => $condition['value'],
|
||||
'#states' => [
|
||||
'visible' => [
|
||||
$trigger_selector => ['value' => 'value'],
|
||||
],
|
||||
],
|
||||
];
|
||||
$row['operations'] = self::buildOperations($table_id, $row_index, $ajax_settings);
|
||||
return $row;
|
||||
}
|
||||
|
||||
/**
|
||||
* Build a state's operations.
|
||||
*
|
||||
* @param string $table_id
|
||||
* The option element's table id.
|
||||
* @param int $row_index
|
||||
* The option's row index.
|
||||
* @param array $ajax_settings
|
||||
* An array containing AJAX callback settings.
|
||||
*
|
||||
* @return array
|
||||
* A render array containing state operations..
|
||||
*/
|
||||
protected static function buildOperations($table_id, $row_index, array $ajax_settings) {
|
||||
$operations = [];
|
||||
$operations['add'] = [
|
||||
'#type' => 'image_button',
|
||||
'#src' => drupal_get_path('module', 'webform') . '/images/icons/plus.svg',
|
||||
'#limit_validation_errors' => [],
|
||||
'#submit' => [[get_called_class(), 'addConditionSubmit']],
|
||||
'#ajax' => $ajax_settings,
|
||||
'#row_index' => $row_index,
|
||||
'#name' => $table_id . '_add_' . $row_index,
|
||||
];
|
||||
$operations['remove'] = [
|
||||
'#type' => 'image_button',
|
||||
'#src' => drupal_get_path('module', 'webform') . '/images/icons/ex.svg',
|
||||
'#limit_validation_errors' => [],
|
||||
'#submit' => [[get_called_class(), 'removeRowSubmit']],
|
||||
'#ajax' => $ajax_settings,
|
||||
'#row_index' => $row_index,
|
||||
'#name' => $table_id . '_remove_' . $row_index,
|
||||
];
|
||||
return $operations;
|
||||
}
|
||||
|
||||
/****************************************************************************/
|
||||
// Callbacks.
|
||||
/****************************************************************************/
|
||||
|
||||
/**
|
||||
* Webform submission handler for adding another state.
|
||||
*
|
||||
* @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 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));
|
||||
|
||||
$values = $element['states']['#value'];
|
||||
|
||||
// Add new state and condition.
|
||||
$values[] = [
|
||||
'state' => '',
|
||||
'operator' => 'and',
|
||||
];
|
||||
$values[] = [
|
||||
'selector' => ['select' => '', 'other' => ''],
|
||||
'trigger' => '',
|
||||
'value' => '',
|
||||
];
|
||||
|
||||
// Update element's #value.
|
||||
$form_state->setValueForElement($element['states'], $values);
|
||||
NestedArray::setValue($form_state->getUserInput(), $element['states']['#parents'], $values);
|
||||
|
||||
// Update the number of rows.
|
||||
$form_state->set(self::getStorageKey($element, 'number_of_rows'), count($values));
|
||||
|
||||
// Rebuild the webform.
|
||||
$form_state->setRebuild();
|
||||
}
|
||||
|
||||
/**
|
||||
* Webform submission handler for adding another condition.
|
||||
*
|
||||
* @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 addConditionSubmit(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, -4));
|
||||
|
||||
// The $row_index is not sequential so we need to rebuild the value instead
|
||||
// of just using an array_slice().
|
||||
$row_index = $button['#row_index'];
|
||||
$values = [];
|
||||
foreach ($element['states']['#value'] as $index => $value) {
|
||||
$values[] = $value;
|
||||
if ($index == $row_index) {
|
||||
$values[] = ['selector' => '', 'trigger' => '', 'value' => ''];
|
||||
}
|
||||
}
|
||||
|
||||
// Reset values.
|
||||
$values = array_values($values);
|
||||
|
||||
// Set values.
|
||||
$form_state->setValueForElement($element['states'], $values);
|
||||
NestedArray::setValue($form_state->getUserInput(), $element['states']['#parents'], $values);
|
||||
|
||||
// Update the number of rows.
|
||||
$form_state->set(self::getStorageKey($element, 'number_of_rows'), count($values));
|
||||
|
||||
// Rebuild the webform.
|
||||
$form_state->setRebuild();
|
||||
}
|
||||
|
||||
/**
|
||||
* Webform submission handler for removing a state or condition.
|
||||
*
|
||||
* @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 removeRowSubmit(array &$form, FormStateInterface $form_state) {
|
||||
$button = $form_state->getTriggeringElement();
|
||||
$element = NestedArray::getValue($form, array_slice($button['#array_parents'], 0, -4));
|
||||
|
||||
$row_index = $button['#row_index'];
|
||||
$values = $element['states']['#value'];
|
||||
|
||||
if (isset($values[$row_index]['state'])) {
|
||||
// Remove state.
|
||||
do {
|
||||
unset($values[$row_index]);
|
||||
$row_index++;
|
||||
} while (isset($values[$row_index]) && !isset($values[$row_index]['state']));
|
||||
}
|
||||
else {
|
||||
// Remove condition.
|
||||
unset($values[$row_index]);
|
||||
}
|
||||
|
||||
// Reset values.
|
||||
$values = array_values($values);
|
||||
|
||||
// Set values.
|
||||
$form_state->setValueForElement($element['states'], $values);
|
||||
NestedArray::setValue($form_state->getUserInput(), $element['states']['#parents'], $values);
|
||||
|
||||
// Update the number of rows.
|
||||
$form_state->set(self::getStorageKey($element, 'number_of_rows'), count($values));
|
||||
|
||||
// Rebuild the webform.
|
||||
$form_state->setRebuild();
|
||||
}
|
||||
|
||||
/**
|
||||
* Webform submission AJAX callback the returns the states table.
|
||||
*/
|
||||
public static function ajaxCallback(array &$form, FormStateInterface $form_state) {
|
||||
$button = $form_state->getTriggeringElement();
|
||||
$parent_length = (isset($button['#row_index'])) ? -4 : -1;
|
||||
$element = NestedArray::getValue($form, array_slice($button['#array_parents'], 0, $parent_length));
|
||||
return $element['states'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates webform states element.
|
||||
*/
|
||||
public static function validateWebformElementStates(&$element, FormStateInterface $form_state, &$complete_form) {
|
||||
if (isset($element['states']['#value']) && is_string($element['states']['#value'])) {
|
||||
$states = Yaml::decode($element['states']['#value']);
|
||||
}
|
||||
else {
|
||||
$states = self::convertFormValuesToFormApiStates($element['states']['#value']);
|
||||
}
|
||||
$form_state->setValueForElement($element, NULL);
|
||||
$form_state->setValueForElement($element, $states);
|
||||
}
|
||||
|
||||
/****************************************************************************/
|
||||
// Helper functions.
|
||||
/****************************************************************************/
|
||||
|
||||
/**
|
||||
* Get unique key used to store the number of options for an element.
|
||||
*
|
||||
* @param array $element
|
||||
* An element.
|
||||
* @param $name
|
||||
* The name.
|
||||
*
|
||||
* @return string
|
||||
* A unique key used to store the number of options for an element.
|
||||
*/
|
||||
protected static function getStorageKey(array $element, $name) {
|
||||
return 'webform_states__' . $element['#name'] . '__' . $name;
|
||||
}
|
||||
|
||||
/****************************************************************************/
|
||||
// Convert functions.
|
||||
/****************************************************************************/
|
||||
|
||||
/**
|
||||
* Convert Form API #states to states array.
|
||||
*
|
||||
* @param array $fapi_states
|
||||
* An associative array containing Form API #states.
|
||||
*
|
||||
* @return array
|
||||
* An associative array of states.
|
||||
*/
|
||||
protected static function convertFormApiStatesToStatesArray(array $fapi_states) {
|
||||
$index = 0;
|
||||
$states = [];
|
||||
foreach ($fapi_states as $state => $conditions) {
|
||||
$states[$index] = [
|
||||
'state' => $state,
|
||||
'operator' => 'and',
|
||||
'conditions' => [],
|
||||
];
|
||||
|
||||
foreach ($conditions as $condition_key => $condition_value) {
|
||||
if (is_string($condition_key)) {
|
||||
$states[$index]['conditions'][] = [
|
||||
'selector' => $condition_key,
|
||||
'trigger' => key($condition_value),
|
||||
'value' => reset($condition_value),
|
||||
];
|
||||
}
|
||||
elseif (is_string($condition_value)) {
|
||||
$states[$index]['operator'] = $condition_value;
|
||||
}
|
||||
else {
|
||||
foreach ($condition_value as $subcondition_key => $subcondition_value) {
|
||||
$states[$index]['conditions'][] = [
|
||||
'selector' => $subcondition_key,
|
||||
'trigger' => key($subcondition_value),
|
||||
'value' => reset($subcondition_value),
|
||||
];
|
||||
}
|
||||
}
|
||||
}
|
||||
$index++;
|
||||
}
|
||||
return $states;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert states array to Form API #states.
|
||||
*
|
||||
* @param array $states_array
|
||||
* An associative array containing states.
|
||||
*
|
||||
* @return array
|
||||
* An associative array of states.
|
||||
*/
|
||||
protected static function convertStatesArrayToFormApiStates(array $states_array = []) {
|
||||
$states = [];
|
||||
foreach ($states_array as $state_array) {
|
||||
if ($state = $state_array['state']) {
|
||||
$operator = $state_array['operator'];
|
||||
$conditions = $state_array['conditions'];
|
||||
if (count($conditions) === 1) {
|
||||
$condition = reset($conditions);
|
||||
$selector = $condition['selector'];
|
||||
$trigger = $condition['trigger'];
|
||||
if ($selector && $trigger) {
|
||||
$value = $condition['value'] ?: TRUE;
|
||||
}
|
||||
else {
|
||||
$value = '';
|
||||
}
|
||||
$states[$state][$selector][$trigger] = $value;
|
||||
}
|
||||
else {
|
||||
foreach ($state_array['conditions'] as $index => $condition) {
|
||||
$selector = $condition['selector'];
|
||||
$trigger = $condition['trigger'];
|
||||
$value = $condition['value'] ?: TRUE;
|
||||
if ($selector && $trigger) {
|
||||
if ($operator == 'or') {
|
||||
if ($index !== 0) {
|
||||
$states[$state][] = $operator;
|
||||
}
|
||||
$states[$state][] = [
|
||||
$selector => [
|
||||
$trigger => $value,
|
||||
],
|
||||
];
|
||||
}
|
||||
else {
|
||||
$states[$state][$selector] = [
|
||||
$trigger => $value,
|
||||
];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
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 convertFormValuesToStatesArray(array $values = []) {
|
||||
$index = 0;
|
||||
|
||||
$states = [];
|
||||
foreach ($values as $value) {
|
||||
if (isset($value['state'])) {
|
||||
$index++;
|
||||
$states[$index] = [
|
||||
'state' => $value['state'],
|
||||
'operator' => $value['operator'],
|
||||
'conditions' => [],
|
||||
];
|
||||
}
|
||||
else {
|
||||
$selector = $value['selector']['select'];
|
||||
if ($selector == WebformSelectOther::OTHER_OPTION) {
|
||||
$selector = $value['selector']['other'];
|
||||
}
|
||||
$value['selector'] = $selector;
|
||||
$states[$index]['conditions'][] = $value;
|
||||
}
|
||||
}
|
||||
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 = self::convertFormValuesToStatesArray($values);
|
||||
return self::convertStatesArrayToFormApiStates($values);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if an element's #states array is customized.
|
||||
*
|
||||
* @param array $element
|
||||
* The webform element.
|
||||
*
|
||||
* @return bool|string
|
||||
* FALSE if #states array is not customized or a warning message.
|
||||
*/
|
||||
public static function isDefaultValueCustomizedFormApiStates(array $element) {
|
||||
// Empty default values are not customized.
|
||||
if (empty($element['#default_value'])) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// #states must always be an array.
|
||||
if (!is_array($element['#default_value'])) {
|
||||
return t('Conditional logic (Form API #states) is not an array.');
|
||||
}
|
||||
|
||||
$states = $element['#default_value'];
|
||||
foreach ($states as $state => $conditions) {
|
||||
if (!isset($element['#state_options'][$state])) {
|
||||
return t('Conditional logic (Form API #states) is using a custom %state state.', ['%state' => $state]);
|
||||
}
|
||||
|
||||
// If associative array we can assume that it not customized.
|
||||
if (WebformArrayHelper::isAssociative(($conditions))) {
|
||||
$trigger = reset($conditions);
|
||||
if (count($trigger) > 1) {
|
||||
return t('Conditional logic (Form API #states) is using multiple triggers.');
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
$operator = NULL;
|
||||
foreach ($conditions as $condition) {
|
||||
// Make sure only one condition is being specified.
|
||||
if (is_array($condition) && count($condition) > 1) {
|
||||
return t('Conditional logic (Form API #states) is using multiple nested conditions.');
|
||||
}
|
||||
elseif (is_string($condition)) {
|
||||
// Make sure only an 'and/or' operator is being used. XOR is not
|
||||
// support in UI because it is confusing to none technicl users.
|
||||
if (!in_array($condition, ['and', 'or'])) {
|
||||
return t('Conditional logic (Form API #states) is using the %operator operator.', ['%operator' => Unicode::strtoupper($condition)]);
|
||||
}
|
||||
|
||||
// Make sure the same operator is being used between the conditions.
|
||||
if ($operator && $operator != $condition) {
|
||||
return t('Conditional logic (Form API #states) has multiple operators.', ['%operator' => Unicode::strtoupper($condition)]);
|
||||
}
|
||||
|
||||
// Set the operator.
|
||||
$operator = $condition;
|
||||
}
|
||||
}
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
}
|
||||
161
web/modules/contrib/webform/src/Element/WebformEmailConfirm.php
Normal file
161
web/modules/contrib/webform/src/Element/WebformEmailConfirm.php
Normal file
|
|
@ -0,0 +1,161 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\webform\Element;
|
||||
|
||||
use Drupal\Component\Utility\Unicode;
|
||||
use Drupal\Core\Render\Element\FormElement;
|
||||
use Drupal\Core\Form\FormStateInterface;
|
||||
use Drupal\Core\Render\Element\CompositeFormElementTrait;
|
||||
|
||||
/**
|
||||
* Provides a webform element requiring users to double-element and confirm an email address.
|
||||
*
|
||||
* Formats as a pair of email addresses fields, which do not validate unless
|
||||
* the two entered email addresses match.
|
||||
*
|
||||
* @FormElement("webform_email_confirm")
|
||||
*/
|
||||
class WebformEmailConfirm extends FormElement {
|
||||
|
||||
use CompositeFormElementTrait;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getInfo() {
|
||||
$class = get_class($this);
|
||||
return [
|
||||
'#input' => TRUE,
|
||||
'#size' => 60,
|
||||
'#process' => [
|
||||
[$class, 'processWebformEmailConfirm'],
|
||||
],
|
||||
'#pre_render' => [
|
||||
[$class, 'preRenderCompositeFormElement'],
|
||||
],
|
||||
'#theme_wrappers' => ['container'],
|
||||
'#required' => FALSE,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function valueCallback(&$element, $input, FormStateInterface $form_state) {
|
||||
if ($input === FALSE) {
|
||||
if (!isset($element['#default_value'])) {
|
||||
$element['#default_value'] = '';
|
||||
}
|
||||
return [
|
||||
'mail_1' => $element['#default_value'],
|
||||
'mail_2' => $element['#default_value'],
|
||||
];
|
||||
}
|
||||
else {
|
||||
return $input;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Expand an email confirm field into two HTML5 email elements.
|
||||
*/
|
||||
public static function processWebformEmailConfirm(&$element, FormStateInterface $form_state, &$complete_form) {
|
||||
$element['#tree'] = TRUE;
|
||||
|
||||
// Get shared properties.
|
||||
$shared_properties = [
|
||||
'#title_display',
|
||||
'#description_display',
|
||||
'#size',
|
||||
'#maxlength',
|
||||
'#pattern',
|
||||
'#required',
|
||||
'#placeholder',
|
||||
'#attributes',
|
||||
];
|
||||
$element_shared_properties = ['#type' => 'email'] + array_intersect_key($element, array_combine($shared_properties, $shared_properties));
|
||||
|
||||
// Get mail 1 email element.
|
||||
$mail_1_properties = [
|
||||
'#title',
|
||||
'#description',
|
||||
];
|
||||
$element['mail_1'] = $element_shared_properties + array_intersect_key($element, array_combine($mail_1_properties, $mail_1_properties));
|
||||
$element['mail_1']['#attributes']['class'][] = 'webform-email';
|
||||
$element['mail_1']['#value'] = empty($element['#value']) ? NULL : $element['#value']['mail_1'];
|
||||
|
||||
// Build mail_2 confirm email element.
|
||||
$element['mail_2'] = $element_shared_properties;
|
||||
$element['mail_2']['#title'] = t('Confirm email');
|
||||
foreach ($element as $key => $value) {
|
||||
if (strpos($key, '#confirm__') === 0) {
|
||||
$element['mail_2'][str_replace('#confirm__', '#', $key)] = $value;
|
||||
}
|
||||
}
|
||||
$element['mail_2']['#attributes']['class'][] = 'webform-email-confirm';
|
||||
$element['mail_2']['#value'] = empty($element['#value']) ? NULL : $element['#value']['mail_2'];
|
||||
|
||||
// Remove properties that are being applied to the sub elements.
|
||||
$element['#required'] = FALSE;
|
||||
unset($element['#title']);
|
||||
unset($element['#description']);
|
||||
unset($element['#maxlength']);
|
||||
unset($element['#atributes']);
|
||||
|
||||
// Set validation.
|
||||
if (isset($element['#element_validate'])) {
|
||||
$element['#element_validate'] = array_merge([[get_called_class(), 'validateWebformEmailConfirm']], $element['#element_validate']);
|
||||
}
|
||||
else {
|
||||
$element['#element_validate'] = [[get_called_class(), 'validateWebformEmailConfirm']];
|
||||
}
|
||||
|
||||
return $element;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates an email confirm element.
|
||||
*/
|
||||
public static function validateWebformEmailConfirm(&$element, FormStateInterface $form_state, &$complete_form) {
|
||||
|
||||
$mail_1 = trim($element['mail_1']['#value']);
|
||||
$mail_2 = trim($element['mail_2']['#value']);
|
||||
$has_access = (!isset($element['#access']) || $element['#access'] === TRUE);
|
||||
if ($has_access) {
|
||||
if ((!empty($mail_1) || !empty($mail_2)) && strcmp($mail_1, $mail_2)) {
|
||||
$form_state->setError($element['mail_2'], t('The specified email addresses do not match.'));
|
||||
}
|
||||
else {
|
||||
// NOTE: Only mail_1 needs to be validated since mail_2 is the same value.
|
||||
// Verify the required value.
|
||||
if ($element['mail_1']['#required'] && empty($mail_1)) {
|
||||
if (isset($element['#required_error'])) {
|
||||
$form_state->setError($element, $element['#required_error']);
|
||||
}
|
||||
elseif (isset($element['mail_1']['#title'])) {
|
||||
$form_state->setError($element, t('@name field is required.', ['@name' => $element['mail_1']['#title']]));
|
||||
}
|
||||
else {
|
||||
$form_state->setError($element);
|
||||
}
|
||||
}
|
||||
// Verify that the value is not longer than #maxlength.
|
||||
if (isset($element['mail_1']['#maxlength']) && Unicode::strlen($mail_1) > $element['mail_1']['#maxlength']) {
|
||||
$t_args = [
|
||||
'@name' => $element['mail_1']['#title'],
|
||||
'%max' => $element['mail_1']['#maxlength'],
|
||||
'%length' => Unicode::strlen($mail_1),
|
||||
];
|
||||
$form_state->setError($element, t('@name cannot be longer than %max characters but is currently %length characters long.', $t_args));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Email field must be converted from a two-element array into a single
|
||||
// string regardless of validation results.
|
||||
$form_state->setValueForElement($element['mail_1'], NULL);
|
||||
$form_state->setValueForElement($element['mail_2'], NULL);
|
||||
$form_state->setValueForElement($element, $mail_1);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,83 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\webform\Element;
|
||||
|
||||
use Drupal\Core\Render\Element;
|
||||
use Drupal\Core\Render\Element\FormElement;
|
||||
use Drupal\Core\Form\FormStateInterface;
|
||||
|
||||
/**
|
||||
* Provides a webform element for entering multiple comma delimited email addresses.
|
||||
*
|
||||
* @FormElement("webform_email_multiple")
|
||||
*/
|
||||
class WebformEmailMultiple extends FormElement {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getInfo() {
|
||||
$class = get_class($this);
|
||||
return [
|
||||
'#input' => TRUE,
|
||||
'#description' => $this->t('Multiple email addresses may be separated by commas.'),
|
||||
'#size' => 60,
|
||||
'#allow_tokens' => FALSE,
|
||||
'#process' => [
|
||||
[$class, 'processAutocomplete'],
|
||||
[$class, 'processAjaxForm'],
|
||||
[$class, 'processPattern'],
|
||||
],
|
||||
'#element_validate' => [
|
||||
[$class, 'validateWebformEmailMultiple'],
|
||||
],
|
||||
'#pre_render' => [
|
||||
[$class, 'preRenderWebformEmailMultiple'],
|
||||
],
|
||||
'#theme' => 'input__email_multiple',
|
||||
'#theme_wrappers' => ['form_element'],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Webform element validation handler for #type 'email_multiple'.
|
||||
*/
|
||||
public static function validateWebformEmailMultiple(&$element, FormStateInterface $form_state, &$complete_form) {
|
||||
$value = trim($element['#value']);
|
||||
$form_state->setValueForElement($element, $value);
|
||||
|
||||
if ($value) {
|
||||
$values = preg_split('/\s*,\s*/', $value);
|
||||
foreach ($values as $value) {
|
||||
// Allow tokens to be be include in multiple email list.
|
||||
if (!empty($element['#allow_tokens'] && preg_match('/^\[.*\]$/', $value))) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!\Drupal::service('email.validator')->isValid($value)) {
|
||||
$form_state->setError($element, t('The email address %mail is not valid.', ['%mail' => $value]));
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepares a #type 'email_multiple' render element for theme_element().
|
||||
*
|
||||
* @param array $element
|
||||
* An associative array containing the properties of the element.
|
||||
* Properties used: #title, #value, #description, #size, #maxlength,
|
||||
* #placeholder, #required, #attributes.
|
||||
*
|
||||
* @return array
|
||||
* The $element with prepared variables ready for theme_element().
|
||||
*/
|
||||
public static function preRenderWebformEmailMultiple(array $element) {
|
||||
$element['#attributes']['type'] = 'text';
|
||||
Element::setAttributes($element, ['id', 'name', 'value', 'size', 'maxlength', 'placeholder']);
|
||||
static::setAttributes($element, ['form-textfield', 'form-email-multiple']);
|
||||
return $element;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\webform\Element;
|
||||
|
||||
use Drupal\Core\Form\FormStateInterface;
|
||||
use Drupal\Core\Render\Element\Checkboxes;
|
||||
|
||||
/**
|
||||
* Provides a webform element for a entity checkboxes.
|
||||
*
|
||||
* @FormElement("webform_entity_checkboxes")
|
||||
*/
|
||||
class WebformEntityCheckboxes extends Checkboxes {
|
||||
|
||||
use WebformEntityTrait;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function processCheckboxes(&$element, FormStateInterface $form_state, &$complete_form) {
|
||||
self::setOptions($element);
|
||||
return parent::processCheckboxes($element, $form_state, $complete_form);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\webform\Element;
|
||||
|
||||
use Drupal\Core\Form\FormStateInterface;
|
||||
use Drupal\Core\Render\Element\Radios;
|
||||
|
||||
/**
|
||||
* Provides a webform element for a entity radios.
|
||||
*
|
||||
* @FormElement("webform_entity_radios")
|
||||
*/
|
||||
class WebformEntityRadios extends Radios {
|
||||
|
||||
use WebformEntityTrait;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function processRadios(&$element, FormStateInterface $form_state, &$complete_form) {
|
||||
self::setOptions($element);
|
||||
return parent::processRadios($element, $form_state, $complete_form);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,32 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\webform\Element;
|
||||
|
||||
use Drupal\Core\Form\FormStateInterface;
|
||||
use Drupal\Core\Render\Element\Select;
|
||||
|
||||
/**
|
||||
* Provides a webform element for a entity select menu.
|
||||
*
|
||||
* @FormElement("webform_entity_select")
|
||||
*/
|
||||
class WebformEntitySelect extends Select {
|
||||
|
||||
use WebformEntityTrait;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function processSelect(&$element, FormStateInterface $form_state, &$complete_form) {
|
||||
self::setOptions($element);
|
||||
$element = parent::processSelect($element, $form_state, $complete_form);
|
||||
|
||||
// Must convert this element['#type'] to a 'select' to prevent
|
||||
// "Illegal choice %choice in %name element" validation error.
|
||||
// @see \Drupal\Core\Form\FormValidator::performRequiredValidation
|
||||
$element['#type'] = 'select';
|
||||
|
||||
return $element;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,69 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\webform\Element;
|
||||
|
||||
use Drupal\Core\Form\OptGroup;
|
||||
use Drupal\webform\Utility\WebformOptionsHelper;
|
||||
|
||||
/**
|
||||
* Trait for entity reference elements.
|
||||
*/
|
||||
trait WebformEntityTrait {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getInfo() {
|
||||
$info = parent::getInfo();
|
||||
$info['#target_type'] = NULL;
|
||||
$info['#selection_handler'] = 'default';
|
||||
$info['#selection_settings'] = [];
|
||||
return $info;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set referencable entities as options for an element.
|
||||
*
|
||||
* @param array $element
|
||||
* An element.
|
||||
*
|
||||
* @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) {
|
||||
if (!empty($element['#options'])) {
|
||||
return;
|
||||
}
|
||||
|
||||
$selection_handler_options = [
|
||||
'target_type' => $element['#target_type'],
|
||||
'handler' => $element['#selection_handler'],
|
||||
'handler_settings' => (isset($element['#selection_settings'])) ? $element['#selection_settings'] : [],
|
||||
];
|
||||
|
||||
/** @var \Drupal\Core\Entity\EntityReferenceSelection\SelectionPluginManagerInterface $selection_manager */
|
||||
$selection_manager = \Drupal::service('plugin.manager.entity_reference_selection');
|
||||
$handler = $selection_manager->getInstance($selection_handler_options);
|
||||
$referenceable_entities = $handler->getReferenceableEntities();
|
||||
|
||||
// Flatten all bundle grouping since they are not applicable to
|
||||
// WebformEntity elements.
|
||||
$options = [];
|
||||
foreach ($referenceable_entities as $bundle_options) {
|
||||
$options += $bundle_options;
|
||||
}
|
||||
|
||||
// Only select menu can support optgroups.
|
||||
if ($element['#type'] !== 'webform_entity_select') {
|
||||
$options = OptGroup::flattenOptions($options);
|
||||
}
|
||||
|
||||
// Issue #2826451: TermSelection returning HTML characters in select list.
|
||||
$options = WebformOptionsHelper::decodeOptions($options);
|
||||
|
||||
$element['#options'] = $options;
|
||||
}
|
||||
|
||||
}
|
||||
116
web/modules/contrib/webform/src/Element/WebformExcludedBase.php
Normal file
116
web/modules/contrib/webform/src/Element/WebformExcludedBase.php
Normal file
|
|
@ -0,0 +1,116 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\webform\Element;
|
||||
|
||||
use Drupal\Core\Form\FormStateInterface;
|
||||
use Drupal\Core\Render\Element\FormElement;
|
||||
|
||||
/**
|
||||
* Provides a base webform element for webform excluded elements and columns.
|
||||
*
|
||||
* This element is just intended to capture all the business logic around
|
||||
* selecting excluded webform elements which is used by the
|
||||
* EmailWebformHandler and the WebformResultsExportForm webforms.
|
||||
*/
|
||||
abstract class WebformExcludedBase extends FormElement {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getInfo() {
|
||||
$class = get_class($this);
|
||||
return [
|
||||
'#input' => TRUE,
|
||||
'#process' => [
|
||||
[$class, 'processWebformExcluded'],
|
||||
],
|
||||
'#webform' => NULL,
|
||||
'#theme_wrappers' => ['form_element'],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Processes a webform elements webform element.
|
||||
*/
|
||||
public static function processWebformExcluded(&$element, FormStateInterface $form_state, &$complete_form) {
|
||||
$options = static::getWebformExcludedOptions($element);
|
||||
|
||||
$default_value = array_diff(array_keys($options), array_keys($element['#default_value'] ?: []));
|
||||
$element['#tree'] = TRUE;
|
||||
$element['#element_validate'] = [[get_called_class(), 'validateWebformExcluded']];
|
||||
|
||||
$element['tableselect'] = [
|
||||
'#type' => 'tableselect',
|
||||
'#header' => static::getWebformExcludedHeader(),
|
||||
'#options' => $options,
|
||||
'#js_select' => TRUE,
|
||||
'#empty' => t('No elements are available.'),
|
||||
'#default_value' => array_combine($default_value, $default_value),
|
||||
];
|
||||
|
||||
// Build tableselect element with selected properties.
|
||||
$properties = [
|
||||
'#title',
|
||||
'#title_display',
|
||||
'#description',
|
||||
'#description_display',
|
||||
'#ajax',
|
||||
'#states',
|
||||
];
|
||||
$element['tableselect'] += array_intersect_key($element, array_combine($properties, $properties));
|
||||
return $element;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates a tablelselect element.
|
||||
*/
|
||||
public static function validateWebformExcluded(array &$element, FormStateInterface $form_state, &$complete_form) {
|
||||
$value = array_filter($element['tableselect']['#value']);
|
||||
|
||||
// Converted value to excluded elements.
|
||||
$options = array_keys($element['tableselect']['#options']);
|
||||
$excluded = array_diff($options, $value);
|
||||
|
||||
// Unset tableselect and set the element's value to excluded.
|
||||
$form_state->setValueForElement($element['tableselect'], NULL);
|
||||
$form_state->setValueForElement($element, array_combine($excluded, $excluded));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get options for excluded tableselect element.
|
||||
*
|
||||
* @param array $element
|
||||
* An associative array containing the properties and children of the
|
||||
* generic element element.
|
||||
*
|
||||
* @return array
|
||||
* An array of options containing title, name, and type of items for a
|
||||
* tableselect element.
|
||||
*/
|
||||
public static function getWebformExcludedOptions(array $element) {
|
||||
/** @var \Drupal\webform\WebformInterface $webform */
|
||||
$webform = $element['#webform'];
|
||||
|
||||
$options = [];
|
||||
$elements = $webform->getElementsInitializedFlattenedAndHasValue('view');
|
||||
foreach ($elements as $key => $element) {
|
||||
$options[$key] = [
|
||||
['title' => $element['#admin_title'] ?:$element['#title'] ?: $key],
|
||||
['name' => $key],
|
||||
['type' => isset($element['#type']) ? $element['#type'] : ''],
|
||||
];
|
||||
}
|
||||
return $options;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get header for the excluded tableselect element.
|
||||
*
|
||||
* @return array
|
||||
* An array container the header for the excluded tableselect element.
|
||||
*/
|
||||
public static function getWebformExcludedHeader() {
|
||||
return [t('Title'), t('Name'), t('Type')];
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,40 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\webform\Element;
|
||||
|
||||
/**
|
||||
* Provides a webform element for webform excluded columns (submission field and elements).
|
||||
*
|
||||
* @FormElement("webform_excluded_columns")
|
||||
*/
|
||||
class WebformExcludedColumns extends WebformExcludedBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function getWebformExcludedHeader() {
|
||||
return [t('Title'), t('Name'), t('Date type/Element type')];
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function getWebformExcludedOptions(array $element) {
|
||||
$options = [];
|
||||
|
||||
/** @var \Drupal\webform\WebformSubmissionStorageInterface $submission_storage */
|
||||
$submission_storage = \Drupal::entityTypeManager()->getStorage('webform_submission');
|
||||
$field_definitions = $submission_storage->getFieldDefinitions();
|
||||
$field_definitions = $submission_storage->checkFieldDefinitionAccess($element['#webform'], $field_definitions);
|
||||
foreach ($field_definitions as $key => $field_definition) {
|
||||
$options[$key] = [
|
||||
['title' => $field_definition['title']],
|
||||
['name' => $key],
|
||||
['type' => $field_definition['type']],
|
||||
];
|
||||
}
|
||||
$options += parent::getWebformExcludedOptions($element);
|
||||
return $options;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\webform\Element;
|
||||
|
||||
/**
|
||||
* Provides a webform element for webform excluded elements.
|
||||
*
|
||||
* @FormElement("webform_excluded_elements")
|
||||
*/
|
||||
class WebformExcludedElements extends WebformExcludedBase {}
|
||||
29
web/modules/contrib/webform/src/Element/WebformFlexbox.php
Normal file
29
web/modules/contrib/webform/src/Element/WebformFlexbox.php
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\webform\Element;
|
||||
|
||||
use Drupal\Core\Form\FormStateInterface;
|
||||
use Drupal\Core\Render\Element\Container;
|
||||
|
||||
/**
|
||||
* Provides a render element for webform flexbox.
|
||||
*
|
||||
* @FormElement("webform_flexbox")
|
||||
*/
|
||||
class WebformFlexbox extends Container {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function processContainer(&$element, FormStateInterface $form_state, &$complete_form) {
|
||||
$element = parent::processContainer($element, $form_state, $complete_form);
|
||||
$element['#attributes']['class'][] = 'webform-flexbox';
|
||||
$element['#attributes']['class'][] = 'js-webform-flexbox';
|
||||
if (isset($element['#align_items'])) {
|
||||
$element['#attributes']['class'][] = 'webform-flexbox--' . $element['#align_items'];
|
||||
}
|
||||
$element['#attached']['library'][] = 'webform/webform.element.flexbox';
|
||||
return $element;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,85 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\webform\Element;
|
||||
|
||||
use Drupal\Component\Utility\Xss;
|
||||
use Drupal\Core\Form\FormStateInterface;
|
||||
use Drupal\Core\Render\Element\Textarea;
|
||||
|
||||
/**
|
||||
* Provides a webform element for entering HTML using CKEditor or CodeMirror.
|
||||
*
|
||||
* @FormElement("webform_html_editor")
|
||||
*/
|
||||
class WebformHtmlEditor extends Textarea {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getInfo() {
|
||||
$class = get_class($this);
|
||||
$info = parent::getInfo();
|
||||
$info['#pre_render'][] = [$class, 'preRenderWebformHtmlEditor'];
|
||||
$info['#element_validate'][] = [$class, 'validateWebformHtmlEditor'];
|
||||
return $info;
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepares a #type 'html_editor' render element for input.html.twig.
|
||||
*
|
||||
* @param array $element
|
||||
* An associative array containing the properties of the element.
|
||||
* Properties used: #title, #value, #return_value, #description, #required,
|
||||
* #attributes, #checked.
|
||||
*
|
||||
* @return array
|
||||
* The $element with prepared variables ready for input.html.twig.
|
||||
*/
|
||||
public static function preRenderWebformHtmlEditor(array $element) {
|
||||
if (\Drupal::config('webform.settings')->get('ui.html_editor_disabled')) {
|
||||
$element['#mode'] = 'html';
|
||||
$element = WebformCodeMirror::preRenderWebformCodeMirror($element);
|
||||
}
|
||||
else {
|
||||
$element['#attached']['library'][] = 'webform/webform.element.html_editor';
|
||||
$element['#attached']['drupalSettings']['webform']['html_editor']['allowedContent'] = self::getAllowedContent();
|
||||
}
|
||||
return $element;
|
||||
}
|
||||
|
||||
/**
|
||||
* Webform element validation handler for #type 'webform_html_editor'.
|
||||
*/
|
||||
public static function validateWebformHtmlEditor(&$element, FormStateInterface $form_state, &$complete_form) {
|
||||
$value = $element['#value'];
|
||||
$form_state->setValueForElement($element, trim($value));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get allowed content.
|
||||
*
|
||||
* @return array
|
||||
* Allowed content (tags) for CKEditor.
|
||||
*/
|
||||
public static function getAllowedContent() {
|
||||
$allowed_tags = \Drupal::config('webform.settings')->get('elements.allowed_tags');
|
||||
switch ($allowed_tags) {
|
||||
case 'admin':
|
||||
$allowed_tags = Xss::getAdminTagList();
|
||||
break;
|
||||
|
||||
case 'html':
|
||||
$allowed_tags = Xss::getHtmlTagList();
|
||||
break;
|
||||
|
||||
default:
|
||||
$allowed_tags = preg_split('/ +/', $allowed_tags);
|
||||
break;
|
||||
}
|
||||
foreach ($allowed_tags as $index => $allowed_tag) {
|
||||
$allowed_tags[$index] .= '(*)[*]{*}';
|
||||
}
|
||||
return implode('; ', $allowed_tags);
|
||||
}
|
||||
|
||||
}
|
||||
17
web/modules/contrib/webform/src/Element/WebformImageFile.php
Normal file
17
web/modules/contrib/webform/src/Element/WebformImageFile.php
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\webform\Element;
|
||||
|
||||
/**
|
||||
* Provides a webform element for an 'image_file' element.
|
||||
*
|
||||
* @FormElement("webform_image_file")
|
||||
*/
|
||||
class WebformImageFile extends WebformManagedFileBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $accept = 'image/*';
|
||||
|
||||
}
|
||||
166
web/modules/contrib/webform/src/Element/WebformLikert.php
Normal file
166
web/modules/contrib/webform/src/Element/WebformLikert.php
Normal file
|
|
@ -0,0 +1,166 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\webform\Element;
|
||||
|
||||
use Drupal\Core\Form\FormStateInterface;
|
||||
use Drupal\Core\Render\Element\FormElement;
|
||||
use Drupal\webform\Utility\WebformArrayHelper;
|
||||
|
||||
/**
|
||||
* Provides a webform element for a likert scale.
|
||||
*
|
||||
* @FormElement("webform_likert")
|
||||
*/
|
||||
class WebformLikert extends FormElement {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getInfo() {
|
||||
$class = get_class($this);
|
||||
return [
|
||||
'#input' => TRUE,
|
||||
'#process' => [
|
||||
[$class, 'processWebformLikert'],
|
||||
[$class, 'processAjaxForm'],
|
||||
],
|
||||
'#theme_wrappers' => ['form_element'],
|
||||
'#required' => FALSE,
|
||||
'#questions' => [],
|
||||
// Using #answers insteads of #options to prevent triggering
|
||||
// \Drupal\Core\Form\FormValidator::performRequiredValidation().
|
||||
'#answers' => [],
|
||||
'#na_answer' => FALSE,
|
||||
'#na_answer_text' => '',
|
||||
'#na_answer_value' => '',
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Processes a likert scale webform element.
|
||||
*/
|
||||
public static function processWebformLikert(&$element, FormStateInterface $form_state, &$complete_form) {
|
||||
// Get answer with optional N/A.
|
||||
self::processWebformLikertAnswers($element);
|
||||
|
||||
// Build header.
|
||||
$header = [
|
||||
'likert_question' => ['question' => FALSE],
|
||||
] + $element['#answers'];
|
||||
|
||||
// Randomize questions.
|
||||
if (!empty($element['#questions_randomize'])) {
|
||||
$element['#questions'] = WebformArrayHelper::shuffle($element['#questions']);
|
||||
}
|
||||
|
||||
// Build rows.
|
||||
$rows = [];
|
||||
foreach ($element['#questions'] as $question_key => $question_title) {
|
||||
$value = (isset($element['#value'][$question_key])) ? $element['#value'][$question_key] : NULL;
|
||||
$row = [];
|
||||
// Must format the label as an item so that inline webform errors will be
|
||||
// displayed.
|
||||
$row['likert_question'] = [
|
||||
'#type' => 'item',
|
||||
'#title' => $question_title,
|
||||
// Must include an empty <span> so that the item's value is
|
||||
// not required.
|
||||
'#value' => '<span></span>',
|
||||
'#required' => $element['#required'],
|
||||
];
|
||||
foreach ($element['#answers'] as $answer_key => $answer_title) {
|
||||
$row[$answer_key] = [
|
||||
'#parents' => [$element['#name'], $question_key],
|
||||
'#type' => 'radio',
|
||||
'#title' => $answer_title,
|
||||
'#title_display' => 'after',
|
||||
// Must cast values as strings to prevent NULL and empty strings.
|
||||
// from being evaluated as 0.
|
||||
'#return_value' => (string) $answer_key,
|
||||
'#value' => (string) $value,
|
||||
];
|
||||
}
|
||||
$rows[$question_key] = $row;
|
||||
}
|
||||
|
||||
$element['table'] = [
|
||||
'#type' => 'table',
|
||||
'#header' => $header,
|
||||
'#attributes' => [
|
||||
'class' => ['webform-likert-table'],
|
||||
'data-likert-answers-count' => count($element['#answers']),
|
||||
],
|
||||
] + $rows;
|
||||
|
||||
// Build table element with selected properties.
|
||||
$properties = [
|
||||
'#states',
|
||||
'#sticky',
|
||||
];
|
||||
$element['table'] += array_intersect_key($element, array_combine($properties, $properties));
|
||||
|
||||
$element['#tree'] = TRUE;
|
||||
$element['#element_validate'] = [[get_called_class(), 'validateWebformLikert']];
|
||||
$element['#attached']['library'][] = 'webform/webform.element.likert';
|
||||
|
||||
return $element;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get likert element's answer which can include an N/A option.
|
||||
*
|
||||
* @param array $element
|
||||
* The element.
|
||||
*/
|
||||
public static function processWebformLikertAnswers(array &$element) {
|
||||
if (empty($element['#na_answer']) || empty($element['#answers'])) {
|
||||
return;
|
||||
}
|
||||
|
||||
$na_value = (!empty($element['#na_answer_value'])) ? $element['#na_answer_value'] : (string) t('N/A');
|
||||
$na_text = (!empty($element['#na_answer_text'])) ? $element['#na_answer_text'] : $na_value;
|
||||
$element['#answers'] += [
|
||||
$na_value => $na_text,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function valueCallback(&$element, $input, FormStateInterface $form_state) {
|
||||
$default_value = [];
|
||||
foreach ($element['#questions'] as $question_key => $question_title) {
|
||||
$default_value[$question_key] = NULL;
|
||||
}
|
||||
|
||||
if ($input === FALSE) {
|
||||
$element += ['#default_value' => []];
|
||||
return $element['#default_value'] + $default_value;
|
||||
}
|
||||
$value = $default_value;
|
||||
foreach ($value as $allowed_key => $default) {
|
||||
if (isset($input[$allowed_key]) && is_scalar($input[$allowed_key])) {
|
||||
$value[$allowed_key] = (string) $input[$allowed_key];
|
||||
}
|
||||
}
|
||||
return $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates a likert element.
|
||||
*/
|
||||
public static function validateWebformLikert(&$element, FormStateInterface $form_state, &$complete_form) {
|
||||
$value = $element['#value'];
|
||||
|
||||
if (!empty($element['#required'])) {
|
||||
foreach ($element['#questions'] as $question_key => $question_title) {
|
||||
if (empty($value[$question_key])) {
|
||||
$form_state->setError($element['table'][$question_key]['likert_question'], t('@name field is required.', ['@name' => $question_title]));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$form_state->setValueForElement($element, $value);
|
||||
}
|
||||
|
||||
}
|
||||
29
web/modules/contrib/webform/src/Element/WebformLink.php
Normal file
29
web/modules/contrib/webform/src/Element/WebformLink.php
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\webform\Element;
|
||||
|
||||
/**
|
||||
* Provides a webform element for a link.
|
||||
*
|
||||
* @FormElement("webform_link")
|
||||
*/
|
||||
class WebformLink extends WebformCompositeBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function getCompositeElements() {
|
||||
$elements = [];
|
||||
$elements['title'] = [
|
||||
'#type' => 'textfield',
|
||||
'#title' => t('Link Title'),
|
||||
'#maxlength' => 255,
|
||||
];
|
||||
$elements['url'] = [
|
||||
'#type' => 'url',
|
||||
'#title' => t('Link URL'),
|
||||
];
|
||||
return $elements;
|
||||
}
|
||||
|
||||
}
|
||||
170
web/modules/contrib/webform/src/Element/WebformLocation.php
Normal file
170
web/modules/contrib/webform/src/Element/WebformLocation.php
Normal file
|
|
@ -0,0 +1,170 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\webform\Element;
|
||||
|
||||
use Drupal\Core\Form\FormStateInterface;
|
||||
|
||||
/**
|
||||
* Provides a webform element for a location element.
|
||||
*
|
||||
* @FormElement("webform_location")
|
||||
*/
|
||||
class WebformLocation extends WebformCompositeBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getInfo() {
|
||||
return parent::getInfo() + [
|
||||
'#api_key' => '',
|
||||
'#hidden' => FALSE,
|
||||
'#geolocation' => FALSE,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function getCompositeElements() {
|
||||
// @see https://developers.google.com/maps/documentation/javascript/geocoding#GeocodingAddressTypes
|
||||
$attributes = [];
|
||||
$attributes['lat'] = [
|
||||
'#title' => t('Latitude'),
|
||||
];
|
||||
$attributes['lng'] = [
|
||||
'#title' => t('Longitude'),
|
||||
];
|
||||
$attributes['location'] = [
|
||||
'#title' => t('Location'),
|
||||
];
|
||||
$attributes['formatted_address'] = [
|
||||
'#title' => t('Formatted Address'),
|
||||
];
|
||||
$attributes['street_address'] = [
|
||||
'#title' => t('Street Address'),
|
||||
];
|
||||
$attributes['street_number'] = [
|
||||
'#title' => t('Street Number'),
|
||||
];
|
||||
$attributes['postal_code'] = [
|
||||
'#title' => t('Postal Code'),
|
||||
];
|
||||
$attributes['locality'] = [
|
||||
'#title' => t('Locality'),
|
||||
];
|
||||
$attributes['sublocality'] = [
|
||||
'#title' => t('City'),
|
||||
];
|
||||
$attributes['administrative_area_level_1'] = [
|
||||
'#title' => t('State/Province'),
|
||||
];
|
||||
$attributes['country'] = [
|
||||
'#title' => t('Country'),
|
||||
];
|
||||
$attributes['country_short'] = [
|
||||
'#title' => t('Country Code'),
|
||||
];
|
||||
|
||||
foreach ($attributes as $name => &$attribute_element) {
|
||||
$attribute_element['#type'] = 'textfield';
|
||||
|
||||
$attribute_element['#attributes'] = [
|
||||
'data-webform-location-attribute' => $name,
|
||||
];
|
||||
}
|
||||
|
||||
$elements = [];
|
||||
$elements['value'] = [
|
||||
'#type' => 'textfield',
|
||||
'#title' => t('Address'),
|
||||
'#attributes' => [
|
||||
'class' => ['webform-location-geocomplete'],
|
||||
],
|
||||
];
|
||||
$elements += $attributes;
|
||||
return $elements;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function preRenderCompositeFormElement($element) {
|
||||
$element = WebformCompositeBase::preRenderCompositeFormElement($element);
|
||||
|
||||
// Hide location element webform display only if #geolocation is also set.
|
||||
if (!empty($element['#hidden']) && !empty($element['#geolocation'])) {
|
||||
$element['#attributes']['style'] = 'display: none';
|
||||
}
|
||||
|
||||
return $element;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function processWebformComposite(&$element, FormStateInterface $form_state, &$complete_form) {
|
||||
$element = parent::processWebformComposite($element, $form_state, $complete_form);
|
||||
|
||||
// Composite elements should always be displayed and rendered so that
|
||||
// location data can be populated, so #access is really just converting the
|
||||
// readonly elements to hidden elements.
|
||||
$composite_elements = static::getCompositeElements();
|
||||
foreach ($composite_elements as $composite_key => $composite_element) {
|
||||
if ($composite_key != 'value') {
|
||||
if (isset($element[$composite_key]['#access']) && $element[$composite_key]['#access'] === FALSE) {
|
||||
unset($element[$composite_key]['#access']);
|
||||
$element[$composite_key]['#type'] = 'hidden';
|
||||
}
|
||||
elseif (!empty($element['#hidden']) && !empty($element['#geolocation'])) {
|
||||
$element[$composite_key]['#type'] = 'hidden';
|
||||
}
|
||||
else {
|
||||
$element[$composite_key]['#attributes']['class'][] = 'webform-readonly';
|
||||
$element[$composite_key]['#readonly'] = 'readonly';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Set required.
|
||||
if (isset($element['#required'])) {
|
||||
$element['value']['#required'] = $element['#required'];
|
||||
}
|
||||
|
||||
// Set Geolocation detection attribute.
|
||||
if (!empty($element['#geolocation'])) {
|
||||
$element['value']['#attributes']['data-webform-location-geolocation'] = 'data-webform-location-geolocation';
|
||||
}
|
||||
|
||||
// Writing script tags (only once) directly into the page's output to ensure
|
||||
// that Google Maps APi script is loaded using the proper API key.
|
||||
static $google_api;
|
||||
if (empty($google_api)) {
|
||||
$api_key = (!empty($element['#api_key'])) ? $element['#api_key'] : \Drupal::config('webform.settings')->get('elements.default_google_maps_api_key');
|
||||
$element['script'] = [
|
||||
'#markup' => '<script src="https://maps.googleapis.com/maps/api/js?key=' . $api_key . '&libraries=places"></script>',
|
||||
'#allowed_tags' => ['script'],
|
||||
];
|
||||
$google_api = TRUE;
|
||||
}
|
||||
|
||||
$element['#attached']['library'][] = 'webform/webform.element.location';
|
||||
|
||||
$element['#element_validate'] = [[get_called_class(), 'validateWebformLocation']];
|
||||
|
||||
return $element;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates location.
|
||||
*/
|
||||
public static function validateWebformLocation(&$element, FormStateInterface $form_state, &$complete_form) {
|
||||
$value = $element['#value'];
|
||||
|
||||
$has_access = (!isset($element['#access']) || $element['#access'] === TRUE);
|
||||
if ($has_access && !empty($element['#required']) && empty($value['location'])) {
|
||||
$t_args = ['@title' => !empty($element['#title']) ? $element['#title'] : t('Location')];
|
||||
$form_state->setError($element, t('The @title is not valid.', $t_args));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,63 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\webform\Element;
|
||||
|
||||
use Drupal\Core\Render\Element\FormElement;
|
||||
use Drupal\file\Element\ManagedFile;
|
||||
|
||||
if (class_exists('\Drupal\file\Element\ManagedFile')) {
|
||||
|
||||
/**
|
||||
* Provides a base class for 'managed_file' elements.
|
||||
*/
|
||||
abstract class WebformManagedFileBase extends ManagedFile {
|
||||
|
||||
/**
|
||||
* The the types of files that the server accepts.
|
||||
*
|
||||
* @var string
|
||||
*
|
||||
* @see http://www.w3schools.com/tags/att_input_accept.asp
|
||||
*/
|
||||
protected static $accept;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getInfo() {
|
||||
$info = parent::getInfo();
|
||||
$info['#pre_render'][] = [get_class($this), 'preRenderWebformManagedFile'];
|
||||
return $info;
|
||||
}
|
||||
|
||||
/**
|
||||
* Render API callback: Adds media capture to the managed_file element type.
|
||||
*/
|
||||
public static function preRenderWebformManagedFile($element) {
|
||||
if (isset($element['upload']) && static::$accept) {
|
||||
$element['upload']['#attributes']['accept'] = static::$accept;;
|
||||
$element['upload']['#attributes']['capture'] = TRUE;
|
||||
}
|
||||
return $element;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
else {
|
||||
|
||||
/**
|
||||
* Provides a empty base class for 'managed_file' elements.
|
||||
*/
|
||||
abstract class WebformManagedFileBase extends FormElement {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getInfo() {
|
||||
return [];
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
21
web/modules/contrib/webform/src/Element/WebformMarkup.php
Normal file
21
web/modules/contrib/webform/src/Element/WebformMarkup.php
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\webform\Element;
|
||||
|
||||
use Drupal\Core\Render\Element\RenderElement;
|
||||
|
||||
/**
|
||||
* Provides a render element for webform markup.
|
||||
*
|
||||
* @FormElement("webform_markup")
|
||||
*/
|
||||
class WebformMarkup extends RenderElement {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getInfo() {
|
||||
return [];
|
||||
}
|
||||
|
||||
}
|
||||
248
web/modules/contrib/webform/src/Element/WebformMessage.php
Normal file
248
web/modules/contrib/webform/src/Element/WebformMessage.php
Normal file
|
|
@ -0,0 +1,248 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\webform\Element;
|
||||
|
||||
use Drupal\Core\Render\Element\RenderElement;
|
||||
use Drupal\Core\Render\Element;
|
||||
use Drupal\Core\Url;
|
||||
|
||||
/**
|
||||
* Provides a render element for message.
|
||||
*
|
||||
* @FormElement("webform_message")
|
||||
*/
|
||||
class WebformMessage extends RenderElement {
|
||||
|
||||
/**
|
||||
* Storage none.
|
||||
*/
|
||||
const STORAGE_NONE = '';
|
||||
|
||||
/**
|
||||
* Storage local.
|
||||
*/
|
||||
const STORAGE_LOCAL = 'local';
|
||||
|
||||
/**
|
||||
* Storage session.
|
||||
*/
|
||||
const STORAGE_SESSION = 'session';
|
||||
|
||||
/**
|
||||
* Storage user (data).
|
||||
*/
|
||||
const STORAGE_USER = 'user';
|
||||
|
||||
/**
|
||||
* Storage state (API).
|
||||
*/
|
||||
const STORAGE_STATE = 'state';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getInfo() {
|
||||
$class = get_class($this);
|
||||
return [
|
||||
'#message_type' => 'status',
|
||||
'#message_message' => '',
|
||||
'#message_close' => FALSE,
|
||||
'#message_close_effect' => 'slide',
|
||||
'#message_id' => '',
|
||||
'#message_storage' => '',
|
||||
'#status_headings' => [],
|
||||
'#pre_render' => [
|
||||
[$class, 'preRenderWebformMessage'],
|
||||
],
|
||||
'#theme_wrappers' => ['webform_message'],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Create status message for rendering.
|
||||
*
|
||||
* @param array $element
|
||||
* An associative array containing the properties and children of the
|
||||
* element.
|
||||
*
|
||||
* @return array
|
||||
* The modified element with status message.
|
||||
*/
|
||||
public static function preRenderWebformMessage(array $element) {
|
||||
$message_type = $element['#message_type'];
|
||||
$message_close = $element['#message_close'];
|
||||
$message_close_effect = $element['#message_close_effect'];
|
||||
$message_id = $element['#message_id'];
|
||||
$message_storage = $element['#message_storage'];
|
||||
$message_message = $element['#message_message'];
|
||||
|
||||
$element['#attributes']['class'][] = 'webform-message';
|
||||
$element['#attributes']['class'][] = 'js-webform-message';
|
||||
|
||||
// Ignore 'user' and 'state' storage is current user is anonymous.
|
||||
if (\Drupal::currentUser()->isAnonymous() && in_array($message_storage, [self::STORAGE_USER, self::STORAGE_STATE])
|
||||
) {
|
||||
$message_storage = '';
|
||||
}
|
||||
|
||||
// Build the messages render array.
|
||||
$messages = [];
|
||||
|
||||
// Add close button as the first message.
|
||||
if ($message_close) {
|
||||
$element['#attributes']['data-message-close-effect'] = $message_close_effect;
|
||||
$element['#attributes']['class'][] = 'webform-message--close';
|
||||
$element['#attributes']['class'][] = 'js-webform-message--close';
|
||||
|
||||
$close_attributes = [
|
||||
'aria-label' => t('close'),
|
||||
'class' => ['js-webform-message__link', 'webform-message__link'],
|
||||
];
|
||||
if (in_array($message_storage, ['user', 'state'])) {
|
||||
$close_url = Url::fromRoute('webform.element.message.close', [
|
||||
'storage' => $message_storage,
|
||||
'id' => $message_id,
|
||||
]);
|
||||
}
|
||||
else {
|
||||
$close_url = Url::fromRoute('<none>', [], ['fragment' => 'close']);
|
||||
}
|
||||
|
||||
$messages[] = [
|
||||
'#type' => 'link',
|
||||
'#title' => '×',
|
||||
'#url' => $close_url,
|
||||
'#attributes' => $close_attributes,
|
||||
];
|
||||
|
||||
// Add close attributes and check is message is closed.
|
||||
if ($message_storage && $message_id) {
|
||||
$element['#attributes']['data-message-id'] = $message_id;
|
||||
$element['#attributes']['data-message-storage'] = $message_storage;
|
||||
$element['#attributes']['class'][] = 'js-webform-message--close-storage';
|
||||
if (self::isClosed($message_storage, $message_id)) {
|
||||
$element['#closed'] = TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Add messages to container children.
|
||||
$messages[] = (!is_array($message_message)) ? ['#markup' => $message_message] : $message_message;
|
||||
foreach (Element::children($element) as $key) {
|
||||
$messages[] = $element[$key];
|
||||
unset($element[$key]);
|
||||
}
|
||||
|
||||
// Add status messages as the message.
|
||||
$element['#message'] = [
|
||||
'#theme' => 'status_messages',
|
||||
'#message_list' => [$message_type => [$messages]],
|
||||
'#status_headings' => $element['#status_headings'] + [
|
||||
'status' => t('Status message'),
|
||||
'error' => t('Error message'),
|
||||
'warning' => t('Warning message'),
|
||||
],
|
||||
];
|
||||
|
||||
$element['#attached']['library'][] = 'webform/webform.element.message';
|
||||
return $element;
|
||||
}
|
||||
|
||||
/****************************************************************************/
|
||||
// Manage closed functions.
|
||||
/****************************************************************************/
|
||||
|
||||
/**
|
||||
* Is message closed via User Data or State API.
|
||||
*
|
||||
* @param string $storage
|
||||
* The storage mechanism to check if a message is closed.
|
||||
* @param string $id
|
||||
* The ID of the message.
|
||||
*
|
||||
* @return bool
|
||||
* TRUE if the message is closed.
|
||||
*/
|
||||
public static function isClosed($storage, $id) {
|
||||
$account = \Drupal::currentUser();
|
||||
$namespace = 'webform.element.message';
|
||||
switch ($storage) {
|
||||
case self::STORAGE_STATE:
|
||||
/** @var \Drupal\Core\State\StateInterface $state */
|
||||
$state = \Drupal::service('state');
|
||||
$values = $state->get($namespace, []);
|
||||
return (isset($values[$id])) ? TRUE : FALSE;
|
||||
|
||||
case self::STORAGE_USER:
|
||||
/** @var \Drupal\user\UserDataInterface $user_data */
|
||||
$user_data = \Drupal::service('user.data');
|
||||
$values = $user_data->get('webform', $account->id(), $namespace) ?: [];
|
||||
return (isset($values[$id])) ? TRUE : FALSE;
|
||||
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set message closed via User Data or State API.
|
||||
*
|
||||
* @param string $storage
|
||||
* The storage mechanism save message closed.
|
||||
* @param string $id
|
||||
* The ID of the message.
|
||||
*
|
||||
* @see \Drupal\webform\Controller\WebformElementController::close
|
||||
*/
|
||||
public static function setClosed($storage, $id) {
|
||||
$account = \Drupal::currentUser();
|
||||
$namespace = 'webform.element.message';
|
||||
switch ($storage) {
|
||||
case self::STORAGE_STATE:
|
||||
/** @var \Drupal\Core\State\StateInterface $state */
|
||||
$state = \Drupal::service('state');
|
||||
$values = $state->get($namespace, []);
|
||||
$values[$id] = TRUE;
|
||||
$state->set($namespace, $values);
|
||||
break;
|
||||
|
||||
case self::STORAGE_USER:
|
||||
/** @var \Drupal\user\UserDataInterface $user_data */
|
||||
$user_data = \Drupal::service('user.data');
|
||||
$values = $user_data->get('webform', $account->id(), $namespace) ?: [];
|
||||
$values[$id] = TRUE;
|
||||
$user_data->set('webform', $account->id(), $namespace, $values);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset message closed via User Data or State API.
|
||||
*
|
||||
* @param string $storage
|
||||
* The storage mechanism save message closed.
|
||||
* @param string $id
|
||||
* The ID of the message.
|
||||
*
|
||||
* @see \Drupal\webform\Controller\WebformElementController::close
|
||||
*/
|
||||
public static function resetClosed($storage, $id) {
|
||||
$account = \Drupal::currentUser();
|
||||
$namespace = 'webform.element.message';
|
||||
switch ($storage) {
|
||||
case self::STORAGE_STATE:
|
||||
/** @var \Drupal\Core\State\StateInterface $state */
|
||||
$state = \Drupal::service('state');
|
||||
$values = $state->get($namespace, []);
|
||||
unset($values[$id]);
|
||||
$state->set($namespace, $values);
|
||||
break;
|
||||
|
||||
case self::STORAGE_USER:
|
||||
/** @var \Drupal\user\UserDataInterface $user_data */
|
||||
$user_data = \Drupal::service('user.data');
|
||||
$values = $user_data->get('webform', $account->id(), $namespace) ?: [];
|
||||
unset($values[$id]);
|
||||
$user_data->set('webform', $account->id(), $namespace, $values);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
576
web/modules/contrib/webform/src/Element/WebformMultiple.php
Normal file
576
web/modules/contrib/webform/src/Element/WebformMultiple.php
Normal file
|
|
@ -0,0 +1,576 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\webform\Element;
|
||||
|
||||
use Drupal\Component\Utility\NestedArray;
|
||||
use Drupal\Core\Render\Element;
|
||||
use Drupal\Core\Render\Element\FormElement;
|
||||
use Drupal\Core\Form\FormStateInterface;
|
||||
use Drupal\webform\Utility\WebformElementHelper;
|
||||
|
||||
/**
|
||||
* Provides a webform element to assist in creation of multiple elements.
|
||||
*
|
||||
* @FormElement("webform_multiple")
|
||||
*/
|
||||
class WebformMultiple extends FormElement {
|
||||
|
||||
/**
|
||||
* Value indicating a element accepts an unlimited number of values.
|
||||
*/
|
||||
const CARDINALITY_UNLIMITED = -1;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getInfo() {
|
||||
$class = get_class($this);
|
||||
return [
|
||||
'#input' => TRUE,
|
||||
'#label' => t('item'),
|
||||
'#labels' => t('items'),
|
||||
'#header' => NULL,
|
||||
'#element' => [
|
||||
'#type' => 'textfield',
|
||||
'#title' => t('Item value'),
|
||||
'#title_display' => 'invisible',
|
||||
'#placeholder' => t('Enter value'),
|
||||
],
|
||||
'#cardinality' => FALSE,
|
||||
'#empty_items' => 1,
|
||||
'#add_more' => 1,
|
||||
'#process' => [
|
||||
[$class, 'processWebformMultiple'],
|
||||
],
|
||||
'#theme_wrappers' => ['form_element'],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function valueCallback(&$element, $input, FormStateInterface $form_state) {
|
||||
if ($input === FALSE) {
|
||||
return (isset($element['#default_value'])) ? $element['#default_value'] : [];
|
||||
}
|
||||
elseif (is_array($input) && isset($input['items'])) {
|
||||
return $input['items'];
|
||||
}
|
||||
else {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Process items and build multiple elements widget.
|
||||
*/
|
||||
public static function processWebformMultiple(&$element, FormStateInterface $form_state, &$complete_form) {
|
||||
$element['#tree'] = TRUE;
|
||||
|
||||
// Add validate callback that extracts the array of items.
|
||||
$element['#element_validate'] = [[get_called_class(), 'validateWebformMultiple']];
|
||||
|
||||
// Wrap this $element in a <div> that handle #states.
|
||||
WebformElementHelper::fixStatesWrapper($element);
|
||||
|
||||
if ($element['#cardinality']) {
|
||||
// If the cardinality is set limit number of items to this value.
|
||||
$number_of_items = $element['#cardinality'];
|
||||
}
|
||||
else {
|
||||
// Get unique key used to store the current number of items.
|
||||
$number_of_items_storage_key = self::getStorageKey($element, 'number_of_items');
|
||||
|
||||
// Store the number of items which is the number of
|
||||
// #default_values + number of empty_items.
|
||||
if ($form_state->get($number_of_items_storage_key) === NULL) {
|
||||
if (empty($element['#default_value']) || !is_array($element['#default_value'])) {
|
||||
$number_of_default_values = 0;
|
||||
}
|
||||
else {
|
||||
$number_of_default_values = count($element['#default_value']);
|
||||
}
|
||||
$number_of_empty_items = (int) $element['#empty_items'];
|
||||
$number_of_items = $number_of_default_values + $number_of_empty_items;
|
||||
if ($number_of_items < 1) {
|
||||
$number_of_items = 1;
|
||||
}
|
||||
$form_state->set($number_of_items_storage_key, $number_of_items);
|
||||
}
|
||||
|
||||
$number_of_items = $form_state->get($number_of_items_storage_key);
|
||||
}
|
||||
$table_id = implode('_', $element['#parents']) . '_table';
|
||||
|
||||
// DEBUG: Disable AJAX callback by commenting out the below callback and
|
||||
// wrapper.
|
||||
$ajax_settings = [
|
||||
'callback' => [get_called_class(), 'ajaxCallback'],
|
||||
'wrapper' => $table_id,
|
||||
];
|
||||
|
||||
$element['#child_keys'] = Element::children($element['#element']);
|
||||
|
||||
// Build (single) element header.
|
||||
$header = self::buildElementHeader($element);
|
||||
|
||||
// Build (single) element rows.
|
||||
$row_index = 0;
|
||||
$weight = 0;
|
||||
$rows = [];
|
||||
|
||||
if (!$form_state->isProcessingInput() && isset($element['#default_value']) && is_array($element['#default_value'])) {
|
||||
$default_values = $element['#default_value'];
|
||||
}
|
||||
elseif ($form_state->isProcessingInput() && isset($element['#value']) && is_array($element['#value'])) {
|
||||
$default_values = $element['#value'];
|
||||
}
|
||||
else {
|
||||
$default_values = [];
|
||||
}
|
||||
|
||||
foreach ($default_values as $default_value) {
|
||||
$rows[$row_index] = self::buildElementRow($table_id, $row_index, $element, $default_value, $weight++, $ajax_settings);
|
||||
$row_index++;
|
||||
}
|
||||
|
||||
while ($row_index < $number_of_items) {
|
||||
$rows[$row_index] = self::buildElementRow($table_id, $row_index, $element, NULL, $weight++, $ajax_settings);
|
||||
$row_index++;
|
||||
}
|
||||
|
||||
// Build table.
|
||||
$element['items'] = [
|
||||
'#prefix' => '<div id="' . $table_id . '" class="webform-multiple-table">',
|
||||
'#suffix' => '</div>',
|
||||
'#type' => 'table',
|
||||
'#header' => $header,
|
||||
'#tabledrag' => [
|
||||
[
|
||||
'action' => 'order',
|
||||
'relationship' => 'sibling',
|
||||
'group' => 'webform-multiple-sort-weight',
|
||||
],
|
||||
],
|
||||
] + $rows;
|
||||
|
||||
// Build add items actions.
|
||||
if (empty($element['#cardinality'])) {
|
||||
$element['add'] = [
|
||||
'#prefix' => '<div class="container-inline">',
|
||||
'#suffix' => '</div>',
|
||||
];
|
||||
$element['add']['submit'] = [
|
||||
'#type' => 'submit',
|
||||
'#value' => t('Add'),
|
||||
'#limit_validation_errors' => [],
|
||||
'#submit' => [[get_called_class(), 'addItemsSubmit']],
|
||||
'#ajax' => $ajax_settings,
|
||||
'#name' => $table_id . '_add',
|
||||
];
|
||||
$element['add']['more_items'] = [
|
||||
'#type' => 'number',
|
||||
'#min' => 1,
|
||||
'#max' => 100,
|
||||
'#default_value' => $element['#add_more'],
|
||||
'#field_suffix' => t('more @labels', ['@labels' => $element['#labels']]),
|
||||
];
|
||||
}
|
||||
|
||||
$element['#attached']['library'][] = 'webform/webform.element.multiple';
|
||||
|
||||
return $element;
|
||||
}
|
||||
|
||||
/**
|
||||
* Build a single element header.
|
||||
*
|
||||
* @param array $element
|
||||
* The element.
|
||||
*
|
||||
* @return array
|
||||
* A render array containing inputs for an element's header.
|
||||
*/
|
||||
public static function buildElementHeader(array $element) {
|
||||
if (empty($element['#header'])) {
|
||||
return [
|
||||
['data' => '', 'colspan' => 4],
|
||||
];
|
||||
}
|
||||
elseif (is_array($element['#header'])) {
|
||||
return $element['#header'];
|
||||
}
|
||||
elseif (is_string($element['#header'])) {
|
||||
return [
|
||||
['data' => $element['#header'], 'colspan' => ($element['#child_keys']) ? count($element['#child_keys']) + 3 : 4],
|
||||
];
|
||||
}
|
||||
else {
|
||||
$header = [];
|
||||
$header['_handle_'] = '';
|
||||
if ($element['#child_keys']) {
|
||||
foreach ($element['#child_keys'] as $child_key) {
|
||||
if (self::isHidden($element['#element'][$child_key])) {
|
||||
continue;
|
||||
}
|
||||
$header[$child_key] = (!empty($element['#element'][$child_key]['#title'])) ? $element['#element'][$child_key]['#title'] : '';
|
||||
}
|
||||
}
|
||||
else {
|
||||
$header['item'] = (isset($element['#element']['#title'])) ? $element['#element']['#title'] : '';
|
||||
}
|
||||
$header['weight'] = t('Weight');
|
||||
if (empty($element['#cardinality'])) {
|
||||
$header['_operations_'] = '';
|
||||
}
|
||||
return $header;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Build a single element row.
|
||||
*
|
||||
* @param string $table_id
|
||||
* The element's table id.
|
||||
* @param int $row_index
|
||||
* The row index.
|
||||
* @param array $element
|
||||
* The element.
|
||||
* @param string $default_value
|
||||
* The default value.
|
||||
* @param int $weight
|
||||
* The weight.
|
||||
* @param array $ajax_settings
|
||||
* An array containing AJAX callback settings.
|
||||
*
|
||||
* @return array
|
||||
* A render array containing inputs for an element's value and weight.
|
||||
*/
|
||||
public static function buildElementRow($table_id, $row_index, array $element, $default_value, $weight, array $ajax_settings) {
|
||||
if ($element['#child_keys']) {
|
||||
foreach ($element['#child_keys'] as $child_key) {
|
||||
if (isset($default_value[$child_key])) {
|
||||
if ($element['#element'][$child_key]['#type'] == 'value') {
|
||||
$element['#element'][$child_key]['#value'] = $default_value[$child_key];
|
||||
}
|
||||
else {
|
||||
$element['#element'][$child_key]['#default_value'] = $default_value[$child_key];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
$element['#element']['#default_value'] = $default_value;
|
||||
}
|
||||
|
||||
$row = [];
|
||||
|
||||
$row['_handle_'] = [];
|
||||
|
||||
if ($element['#child_keys'] && !empty($element['#header'])) {
|
||||
foreach ($element['#child_keys'] as $child_key) {
|
||||
// Store hidden element in the '_handle_' column.
|
||||
// @see \Drupal\webform\Element\WebformMultiple::convertValuesToItems
|
||||
if (self::isHidden($element['#element'][$child_key])) {
|
||||
$row['_handle_'][$child_key] = $element['#element'][$child_key];
|
||||
// ISSUE: All elements in _handle_ are losing their value.
|
||||
// WORKAROUND: Convert to element to rendered hidden field.
|
||||
$row['_handle_'][$child_key]['#type'] = 'hidden';
|
||||
unset($row['_handle_'][$child_key]['#access']);
|
||||
}
|
||||
else {
|
||||
$row[$child_key] = $element['#element'][$child_key];
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
$row['_item_'] = $element['#element'];
|
||||
}
|
||||
|
||||
$row['weight'] = [
|
||||
'#type' => 'weight',
|
||||
'#delta' => 1000,
|
||||
'#title' => t('Item weight'),
|
||||
'#title_display' => 'invisible',
|
||||
'#attributes' => [
|
||||
'class' => ['webform-multiple-sort-weight'],
|
||||
],
|
||||
'#default_value' => $weight,
|
||||
];
|
||||
|
||||
// Allow users to add & remove rows if cardinality is not set.
|
||||
if (empty($element['#cardinality'])) {
|
||||
$row['_operations_'] = [];
|
||||
$row['_operations_']['add'] = [
|
||||
'#type' => 'image_button',
|
||||
'#src' => drupal_get_path('module', 'webform') . '/images/icons/plus.svg',
|
||||
'#limit_validation_errors' => [],
|
||||
'#submit' => [[get_called_class(), 'addItemSubmit']],
|
||||
'#ajax' => $ajax_settings,
|
||||
// Issue #1342066 Document that buttons with the same #value need a unique
|
||||
// #name for the Form API to distinguish them, or change the Form API to
|
||||
// assign unique #names automatically.
|
||||
'#row_index' => $row_index,
|
||||
'#name' => $table_id . '_add_' . $row_index,
|
||||
];
|
||||
$row['_operations_']['remove'] = [
|
||||
'#type' => 'image_button',
|
||||
'#src' => drupal_get_path('module', 'webform') . '/images/icons/ex.svg',
|
||||
'#limit_validation_errors' => [],
|
||||
'#submit' => [[get_called_class(), 'removeItemSubmit']],
|
||||
'#ajax' => $ajax_settings,
|
||||
// Issue #1342066 Document that buttons with the same #value need a unique
|
||||
// #name for the Form API to distinguish them, or change the Form API to
|
||||
// assign unique #names automatically.
|
||||
'#row_index' => $row_index,
|
||||
'#name' => $table_id . '_remove_' . $row_index,
|
||||
];
|
||||
}
|
||||
|
||||
$row['#weight'] = $weight;
|
||||
$row['#attributes']['class'][] = 'draggable';
|
||||
return $row;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if an element is hidden.
|
||||
*
|
||||
* @param array $element
|
||||
* The element.
|
||||
*
|
||||
* @return bool
|
||||
* TRUE if the element is hidden.
|
||||
*/
|
||||
protected static function isHidden(array $element) {
|
||||
if (isset($element['#access']) && $element['#access'] === FALSE) {
|
||||
return TRUE;
|
||||
}
|
||||
elseif (isset($element['#type']) && in_array($element['#type'], ['hidden', 'value'])) {
|
||||
return TRUE;
|
||||
}
|
||||
else {
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
/****************************************************************************/
|
||||
// Callbacks.
|
||||
/****************************************************************************/
|
||||
|
||||
/**
|
||||
* Webform submission handler for adding more items.
|
||||
*
|
||||
* @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 addItemsSubmit(array &$form, FormStateInterface $form_state) {
|
||||
// Get the webform list element by going up two levels.
|
||||
$button = $form_state->getTriggeringElement();
|
||||
$element =& NestedArray::getValue($form, array_slice($button['#array_parents'], 0, -2));
|
||||
|
||||
// Add more items to the number of items.
|
||||
$number_of_items_storage_key = self::getStorageKey($element, 'number_of_items');
|
||||
$number_of_items = $form_state->get($number_of_items_storage_key);
|
||||
$more_items = (int) $element['add']['more_items']['#value'];
|
||||
$form_state->set($number_of_items_storage_key, $number_of_items + $more_items);
|
||||
|
||||
// Reset values.
|
||||
$element['items']['#value'] = array_values($element['items']['#value']);
|
||||
$form_state->setValueForElement($element['items'], $element['items']['#value']);
|
||||
NestedArray::setValue($form_state->getUserInput(), $element['items']['#parents'], $element['items']['#value']);
|
||||
|
||||
// Rebuild the webform.
|
||||
$form_state->setRebuild();
|
||||
}
|
||||
|
||||
/**
|
||||
* Webform submission handler for adding an item.
|
||||
*
|
||||
* @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 addItemSubmit(array &$form, FormStateInterface $form_state) {
|
||||
$button = $form_state->getTriggeringElement();
|
||||
$element = NestedArray::getValue($form, array_slice($button['#array_parents'], 0, -4));
|
||||
|
||||
// Add item.
|
||||
$values = [];
|
||||
foreach ($element['items']['#value'] as $row_index => $value) {
|
||||
$values[] = $value;
|
||||
if ($row_index == $button['#row_index']) {
|
||||
$values[] = ['item' => '', 'text' => ''];
|
||||
}
|
||||
}
|
||||
|
||||
// Add one item to the 'number of items'.
|
||||
$number_of_items_storage_key = self::getStorageKey($element, 'number_of_items');
|
||||
$number_of_items = $form_state->get($number_of_items_storage_key);
|
||||
$form_state->set($number_of_items_storage_key, $number_of_items + 1);
|
||||
|
||||
// Reset values.
|
||||
$form_state->setValueForElement($element['items'], $values);
|
||||
NestedArray::setValue($form_state->getUserInput(), $element['items']['#parents'], $values);
|
||||
|
||||
// Rebuild the webform.
|
||||
$form_state->setRebuild();
|
||||
}
|
||||
|
||||
/**
|
||||
* Webform submission handler for removing an item.
|
||||
*
|
||||
* @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 removeItemSubmit(array &$form, FormStateInterface $form_state) {
|
||||
$button = $form_state->getTriggeringElement();
|
||||
$element = NestedArray::getValue($form, array_slice($button['#array_parents'], 0, -4));
|
||||
$values = $element['items']['#value'];
|
||||
|
||||
// Remove item.
|
||||
unset($values[$button['#row_index']]);
|
||||
$values = array_values($values);
|
||||
|
||||
// Remove one item from the 'number of items'.
|
||||
$number_of_items_storage_key = self::getStorageKey($element, 'number_of_items');
|
||||
$number_of_items = $form_state->get($number_of_items_storage_key);
|
||||
// Never allow the number of items to be less than 1.
|
||||
if ($number_of_items != 1) {
|
||||
$form_state->set($number_of_items_storage_key, $number_of_items - 1);
|
||||
}
|
||||
|
||||
// Reset values.
|
||||
$form_state->setValueForElement($element['items'], $values);
|
||||
NestedArray::setValue($form_state->getUserInput(), $element['items']['#parents'], $values);
|
||||
|
||||
// Rebuild the webform.
|
||||
$form_state->setRebuild();
|
||||
}
|
||||
|
||||
/**
|
||||
* Webform submission AJAX callback the returns the list table.
|
||||
*/
|
||||
public static function ajaxCallback(array &$form, FormStateInterface $form_state) {
|
||||
$button = $form_state->getTriggeringElement();
|
||||
$parent_length = (isset($button['#row_index'])) ? -4 : -2;
|
||||
$element = NestedArray::getValue($form, array_slice($button['#array_parents'], 0, $parent_length));
|
||||
return $element['items'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates webform list element.
|
||||
*/
|
||||
public static function validateWebformMultiple(&$element, FormStateInterface $form_state, &$complete_form) {
|
||||
// IMPORTANT: Must get values from the $form_states since sub-elements
|
||||
// may call $form_state->setValueForElement() via their validation hook.
|
||||
// @see \Drupal\webform\Element\WebformEmailConfirm::validateWebformEmailConfirm
|
||||
// @see \Drupal\webform\Element\WebformOtherBase::validateWebformOther
|
||||
$values = NestedArray::getValue($form_state->getValues(), $element['#parents']);
|
||||
|
||||
// Convert values to items.
|
||||
$items = self::convertValuesToItems($values['items']);
|
||||
|
||||
// Validate required items.
|
||||
if (!empty($element['#required']) && empty($items)) {
|
||||
if (isset($element['#required_error'])) {
|
||||
$form_state->setError($element, $element['#required_error']);
|
||||
}
|
||||
elseif (isset($element['#title'])) {
|
||||
$form_state->setError($element, t('@name field is required.', ['@name' => $element['#title']]));
|
||||
}
|
||||
else {
|
||||
$form_state->setError($element);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
$form_state->setValueForElement($element, $items);
|
||||
}
|
||||
|
||||
/****************************************************************************/
|
||||
// Helper functions.
|
||||
/****************************************************************************/
|
||||
|
||||
/**
|
||||
* Get unique key used to store the number of items for an element.
|
||||
*
|
||||
* @param array $element
|
||||
* An element.
|
||||
*
|
||||
* @return string
|
||||
* A unique key used to store the number of items for an element.
|
||||
*/
|
||||
public static function getStorageKey(array $element, $name) {
|
||||
return 'webform_multiple__' . $element['#name'] . '__' . $name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert an array containing of values (elements or _item_ and weight) to an array of items.
|
||||
*
|
||||
* @param array $values
|
||||
* An array containing of item and weight.
|
||||
*
|
||||
* @return array
|
||||
* An array of items.
|
||||
*/
|
||||
public static function convertValuesToItems(array $values = []) {
|
||||
// Sort the item values.
|
||||
uasort($values, ['Drupal\Component\Utility\SortArray', 'sortByWeightElement']);
|
||||
|
||||
// Now build the associative array of items.
|
||||
$items = [];
|
||||
foreach ($values as $value) {
|
||||
if (isset($value['_item_'])) {
|
||||
if (!self::isEmpty($value['_item_'])) {
|
||||
$items[] = $value['_item_'];
|
||||
}
|
||||
}
|
||||
else {
|
||||
// Get hidden (#access: FALSE) elements in the '_handle_' column and
|
||||
// add them to the $value.
|
||||
// @see \Drupal\webform\Element\WebformMultiple::buildElementRow
|
||||
if (isset($value['_handle_']) && is_array($value['_handle_'])) {
|
||||
$value += $value['_handle_'];
|
||||
}
|
||||
unset($value['weight'], $value['_operations_'], $value['_handle_']);
|
||||
if (!self::isEmpty($value)) {
|
||||
$items[] = $value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $items;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if array is empty.
|
||||
*
|
||||
* @param string|array $value
|
||||
* An item.
|
||||
*
|
||||
* @return bool
|
||||
* FALSE if item is an empty string or an empty array.
|
||||
*/
|
||||
public static function isEmpty($value = NULL) {
|
||||
if (is_null($value)) {
|
||||
return TRUE;
|
||||
}
|
||||
elseif (is_string($value)) {
|
||||
return ($value === '') ? TRUE : FALSE;
|
||||
}
|
||||
elseif (is_array($value)) {
|
||||
return !array_filter($value, function ($item) {
|
||||
return !self::isEmpty($item);
|
||||
});
|
||||
}
|
||||
else {
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
45
web/modules/contrib/webform/src/Element/WebformName.php
Normal file
45
web/modules/contrib/webform/src/Element/WebformName.php
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\webform\Element;
|
||||
|
||||
/**
|
||||
* Provides a webform element for an name element.
|
||||
*
|
||||
* @FormElement("webform_name")
|
||||
*/
|
||||
class WebformName extends WebformCompositeBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function getCompositeElements() {
|
||||
$elements = [];
|
||||
$elements['title'] = [
|
||||
'#type' => 'webform_select_other',
|
||||
'#title' => t('Title'),
|
||||
'#options' => 'titles',
|
||||
];
|
||||
$elements['first'] = [
|
||||
'#type' => 'textfield',
|
||||
'#title' => t('First'),
|
||||
];
|
||||
$elements['middle'] = [
|
||||
'#type' => 'textfield',
|
||||
'#title' => t('Middle'),
|
||||
];
|
||||
$elements['last'] = [
|
||||
'#type' => 'textfield',
|
||||
'#title' => t('Last'),
|
||||
];
|
||||
$elements['suffix'] = [
|
||||
'#type' => 'textfield',
|
||||
'#title' => t('Suffix'),
|
||||
];
|
||||
$elements['degree'] = [
|
||||
'#type' => 'textfield',
|
||||
'#title' => t('Degree'),
|
||||
];
|
||||
return $elements;
|
||||
}
|
||||
|
||||
}
|
||||
208
web/modules/contrib/webform/src/Element/WebformOptions.php
Normal file
208
web/modules/contrib/webform/src/Element/WebformOptions.php
Normal file
|
|
@ -0,0 +1,208 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\webform\Element;
|
||||
|
||||
use Drupal\Component\Utility\NestedArray;
|
||||
use Drupal\Core\Serialization\Yaml;
|
||||
use Drupal\Core\Render\Element\FormElement;
|
||||
use Drupal\Core\Form\FormStateInterface;
|
||||
use Drupal\webform\Utility\WebformElementHelper;
|
||||
|
||||
/**
|
||||
* Provides a webform element to assist in creation of options.
|
||||
*
|
||||
* This provides a nicer interface for non-technical users to add values and
|
||||
* labels for options, possible within option groups.
|
||||
*
|
||||
* @FormElement("webform_options")
|
||||
*/
|
||||
class WebformOptions extends FormElement {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getInfo() {
|
||||
$class = get_class($this);
|
||||
return [
|
||||
'#input' => TRUE,
|
||||
'#label' => t('option'),
|
||||
'#labels' => t('options'),
|
||||
'#empty_items' => 5,
|
||||
'#add_more' => 1,
|
||||
'#process' => [
|
||||
[$class, 'processWebformOptions'],
|
||||
],
|
||||
'#theme_wrappers' => ['form_element'],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function valueCallback(&$element, $input, FormStateInterface $form_state) {
|
||||
if ($input === FALSE) {
|
||||
if (!isset($element['#default_value'])) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$options = (is_string($element['#default_value'])) ? Yaml::decode($element['#default_value']) : $element['#default_value'];
|
||||
if (self::hasOptGroup($options)) {
|
||||
return $options;
|
||||
}
|
||||
return self::convertOptionsToValues($options);
|
||||
}
|
||||
elseif (is_array($input) && isset($input['options'])) {
|
||||
return (is_string($input['options'])) ? Yaml::decode($input['options']) : $input['options'];
|
||||
}
|
||||
else {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Process options and build options widget.
|
||||
*/
|
||||
public static function processWebformOptions(&$element, FormStateInterface $form_state, &$complete_form) {
|
||||
$element['#tree'] = TRUE;
|
||||
|
||||
// Add validate callback that extracts the associative array of options.
|
||||
$element['#element_validate'] = [[get_called_class(), 'validateWebformOptions']];
|
||||
|
||||
// Wrap this $element in a <div> that handle #states.
|
||||
WebformElementHelper::fixStatesWrapper($element);
|
||||
|
||||
// For options with optgroup display a CodeMirror YAML editor.
|
||||
if (isset($element['#default_value']) && is_array($element['#default_value']) && self::hasOptGroup($element['#default_value'])) {
|
||||
// Build table.
|
||||
$element['options'] = [
|
||||
'#type' => 'webform_codemirror',
|
||||
'#mode' => 'yaml',
|
||||
'#default_value' => Yaml::encode($element['#default_value']),
|
||||
'#description' => t('Key-value pairs MUST be specified as "safe_key: \'Some readable options\'". Use of only alphanumeric characters and underscores is recommended in keys. One option per line.') . '<br/>' .
|
||||
t('Option groups can be created by using just the group name followed by indented group options.'),
|
||||
];
|
||||
return $element;
|
||||
}
|
||||
else {
|
||||
$properties = ['#label', '#labels', '#empty_items', '#add_more'];
|
||||
$element['options'] = array_intersect_key($element, array_combine($properties, $properties)) + [
|
||||
'#type' => 'webform_multiple',
|
||||
'#header' => TRUE,
|
||||
'#element' => [
|
||||
'value' => [
|
||||
'#type' => 'textfield',
|
||||
'#title' => t('Option value'),
|
||||
'#title_display' => t('invisible'),
|
||||
'#placeholder' => t('Enter value'),
|
||||
],
|
||||
'text' => [
|
||||
'#type' => 'textfield',
|
||||
'#title' => t('Option text'),
|
||||
'#title_display' => t('invisible'),
|
||||
'#placeholder' => t('Enter text'),
|
||||
],
|
||||
],
|
||||
'#default_value' => (isset($element['#default_value'])) ? self::convertOptionsToValues($element['#default_value']) : [],
|
||||
];
|
||||
return $element;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates webform options element.
|
||||
*/
|
||||
public static function validateWebformOptions(&$element, FormStateInterface $form_state, &$complete_form) {
|
||||
$options_value = NestedArray::getValue($form_state->getValues(), $element['options']['#parents']);
|
||||
|
||||
if (is_string($options_value)) {
|
||||
$options = Yaml::decode($options_value);
|
||||
}
|
||||
else {
|
||||
$options = self::convertValuesToOptions($options_value);
|
||||
}
|
||||
|
||||
// Validate required options.
|
||||
if (!empty($element['#required']) && empty($options)) {
|
||||
if (isset($element['#required_error'])) {
|
||||
$form_state->setError($element, $element['#required_error']);
|
||||
}
|
||||
elseif (isset($element['#title'])) {
|
||||
$form_state->setError($element, t('@name field is required.', ['@name' => $element['#title']]));
|
||||
}
|
||||
else {
|
||||
$form_state->setError($element);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
$form_state->setValueForElement($element, $options);
|
||||
}
|
||||
|
||||
/****************************************************************************/
|
||||
// Helper functions.
|
||||
/****************************************************************************/
|
||||
|
||||
/**
|
||||
* Convert values from yamform_multiple element to options.
|
||||
*
|
||||
* @param array $values
|
||||
* An array of values.
|
||||
*
|
||||
* @return array
|
||||
* An array of options.
|
||||
*/
|
||||
public static function convertValuesToOptions(array $values = []) {
|
||||
$options = [];
|
||||
foreach ($values as $value) {
|
||||
$option_value = $value['value'];
|
||||
$option_text = $value['text'];
|
||||
|
||||
// Populate empty option value or option text.
|
||||
if ($option_value === '') {
|
||||
$option_value = $option_text;
|
||||
}
|
||||
elseif ($option_text === '') {
|
||||
$option_text = $option_value;
|
||||
}
|
||||
|
||||
$options[$option_value] = $option_text;
|
||||
}
|
||||
return $options;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert options to values for yamform_multiple element.
|
||||
*
|
||||
* @param array $options
|
||||
* An array of options.
|
||||
*
|
||||
* @return array
|
||||
* An array of values.
|
||||
*/
|
||||
public static function convertOptionsToValues(array $options = []) {
|
||||
$values = [];
|
||||
foreach ($options as $value => $text) {
|
||||
$values[] = ['value' => $value, 'text' => $text];
|
||||
}
|
||||
return $values;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if options array contains an OptGroup.
|
||||
*
|
||||
* @param array $options
|
||||
* An array of options.
|
||||
*
|
||||
* @return bool
|
||||
* TRUE if options array contains an OptGroup.
|
||||
*/
|
||||
public static function hasOptGroup(array $options) {
|
||||
foreach ($options as $option_text) {
|
||||
if (is_array($option_text)) {
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
}
|
||||
300
web/modules/contrib/webform/src/Element/WebformOtherBase.php
Normal file
300
web/modules/contrib/webform/src/Element/WebformOtherBase.php
Normal file
|
|
@ -0,0 +1,300 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\webform\Element;
|
||||
|
||||
use Drupal\Component\Utility\NestedArray;
|
||||
use Drupal\Core\Form\FormStateInterface;
|
||||
use Drupal\Core\Form\OptGroup;
|
||||
use Drupal\Core\Render\Element\FormElement;
|
||||
use Drupal\webform\Utility\WebformOptionsHelper;
|
||||
|
||||
/**
|
||||
* Base class for webform other element.
|
||||
*/
|
||||
abstract class WebformOtherBase extends FormElement {
|
||||
|
||||
/**
|
||||
* Other option value.
|
||||
*/
|
||||
const OTHER_OPTION = '_other_';
|
||||
|
||||
/**
|
||||
* The type of element.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected static $type;
|
||||
|
||||
/**
|
||||
* The properties of the element.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected static $properties = [
|
||||
'#required',
|
||||
'#options',
|
||||
'#options_display',
|
||||
'#default_value',
|
||||
'#attributes',
|
||||
];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getInfo() {
|
||||
$class = get_class($this);
|
||||
return [
|
||||
'#input' => TRUE,
|
||||
'#process' => [
|
||||
[$class, 'processWebformOther'],
|
||||
[$class, 'processAjaxForm'],
|
||||
],
|
||||
'#theme_wrappers' => ['form_element'],
|
||||
'#options' => [],
|
||||
'#other__option_delimiter' => ', ',
|
||||
'#states' => [],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function valueCallback(&$element, $input, FormStateInterface $form_state) {
|
||||
// Remove 'webform_' prefix from type.
|
||||
$type = str_replace('webform_', '', static::$type);
|
||||
|
||||
if ($input === FALSE) {
|
||||
$value = self::convertDefaultValueToElementValue($element);
|
||||
$element[$type]['#default_value'] = $value[$type];
|
||||
if ($value['other'] !== NULL) {
|
||||
$element['other']['#default_value'] = $value['other'];
|
||||
}
|
||||
return $value;
|
||||
}
|
||||
|
||||
// Return NULL so that current $input is used.
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Processes an 'other' element.
|
||||
*
|
||||
* See select list webform element for select list properties.
|
||||
*
|
||||
* @see \Drupal\Core\Render\Element\Select
|
||||
*/
|
||||
public static function processWebformOther(&$element, FormStateInterface $form_state, &$complete_form) {
|
||||
// Remove 'webform_' prefix from type.
|
||||
$type = str_replace('webform_', '', static::$type);
|
||||
$properties = static::$properties;
|
||||
|
||||
$element['#tree'] = TRUE;
|
||||
|
||||
$element['#wrapper_attributes']['class'][] = "js-webform-$type-other";
|
||||
$element['#wrapper_attributes']['class'][] = "webform-$type-other";
|
||||
|
||||
$element[$type]['#type'] = static::$type;
|
||||
$element[$type] += array_intersect_key($element, array_combine($properties, $properties));
|
||||
if (!isset($element[$type]['#options'][static::OTHER_OPTION])) {
|
||||
$element[$type]['#options'][static::OTHER_OPTION] = (!empty($element['#other__option_label'])) ? $element['#other__option_label'] : t('Other...');
|
||||
}
|
||||
$element[$type]['#error_no_message'] = TRUE;
|
||||
|
||||
// Build other textfield.
|
||||
$element['other']['#error_no_message'] = TRUE;
|
||||
foreach ($element as $key => $value) {
|
||||
if (strpos($key, '#other__') === 0) {
|
||||
$other_key = str_replace('#other__', '#', $key);
|
||||
if (!isset($element['other'][$other_key])) {
|
||||
$element['other'][$other_key] = $value;
|
||||
}
|
||||
}
|
||||
}
|
||||
$element['other'] += [
|
||||
'#type' => 'textfield',
|
||||
'#placeholder' => t('Enter other...'),
|
||||
];
|
||||
$element['other']['#wrapper_attributes']['class'][] = "js-webform-$type-other-input";
|
||||
$element['other']['#wrapper_attributes']['class'][] = "webform-$type-other-input";
|
||||
|
||||
// Remove options.
|
||||
unset($element['#options']);
|
||||
|
||||
// Set validation.
|
||||
if (isset($element['#element_validate'])) {
|
||||
$element['#element_validate'] = array_merge([[get_called_class(), 'validateWebformOther']], $element['#element_validate']);
|
||||
}
|
||||
else {
|
||||
$element['#element_validate'] = [[get_called_class(), 'validateWebformOther']];
|
||||
}
|
||||
|
||||
// Attach library.
|
||||
$element['#attached']['library'][] = 'webform/webform.element.other';
|
||||
|
||||
// Process states.
|
||||
webform_process_states($element, '#wrapper_attributes');
|
||||
|
||||
return $element;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates an other element.
|
||||
*/
|
||||
public static function validateWebformOther(&$element, FormStateInterface $form_state, &$complete_form) {
|
||||
// Determine if the element is visible. (#access !== FALSE)
|
||||
$has_access = (!isset($element['#access']) || $element['#access'] === TRUE);
|
||||
|
||||
// Remove 'webform_' prefix from type.
|
||||
$type = str_replace('webform_', '', static::$type);
|
||||
|
||||
// Get value.
|
||||
$value = NestedArray::getValue($form_state->getValues(), $element['#parents']);
|
||||
|
||||
// Get return value.
|
||||
$return_value = [];
|
||||
$element_value = $value[$type];
|
||||
$other_value = $value['other'];
|
||||
if (static::isMultiple($element)) {
|
||||
$element_value = array_filter($element_value);
|
||||
$return_value += $element_value;
|
||||
if (isset($element_value[static::OTHER_OPTION])) {
|
||||
unset($return_value[static::OTHER_OPTION]);
|
||||
if ($has_access && $other_value === '') {
|
||||
static::setOtherError($element, $form_state);
|
||||
return;
|
||||
}
|
||||
$return_value += [$other_value => $other_value];
|
||||
}
|
||||
}
|
||||
else {
|
||||
$return_value = $element_value;
|
||||
if ($element_value == static::OTHER_OPTION) {
|
||||
if ($has_access && $other_value === '') {
|
||||
static::setOtherError($element, $form_state);
|
||||
return;
|
||||
}
|
||||
else {
|
||||
$return_value = $other_value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Determine if the return value is empty.
|
||||
if (static::isMultiple($element)) {
|
||||
$is_empty = (empty($return_value)) ? TRUE : FALSE;
|
||||
}
|
||||
else {
|
||||
$is_empty = ($return_value === '' || $return_value === NULL) ? TRUE : FALSE;
|
||||
}
|
||||
|
||||
// Handler required validation.
|
||||
if ($element['#required'] && $is_empty && $has_access) {
|
||||
static::setElementError($element, $form_state);
|
||||
}
|
||||
|
||||
$form_state->setValueForElement($element[$type], NULL);
|
||||
$form_state->setValueForElement($element['other'], NULL);
|
||||
$form_state->setValueForElement($element, $return_value);
|
||||
}
|
||||
|
||||
/****************************************************************************/
|
||||
// Helper functions.
|
||||
/****************************************************************************/
|
||||
|
||||
/**
|
||||
* Determine if the webform element contains multiple values.
|
||||
*
|
||||
* @param array $element
|
||||
* A webform element.
|
||||
*
|
||||
* @return bool
|
||||
* TRUE if the webform element contains multiple values.
|
||||
*/
|
||||
protected static function isMultiple(array $element) {
|
||||
return (!empty($element['#multiple']) || static::$type == 'checkboxes') ? TRUE : FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert default value to element value.
|
||||
*
|
||||
* @param array $element
|
||||
* A other form element.
|
||||
*
|
||||
* @return array
|
||||
* An associative array container (element) type and other value.
|
||||
*/
|
||||
protected static function convertDefaultValueToElementValue($element) {
|
||||
$type = str_replace('webform_', '', static::$type);
|
||||
|
||||
$default_value = isset($element['#default_value']) ? $element['#default_value'] : NULL;
|
||||
if (static::isMultiple($element)) {
|
||||
// Handle edge case where $default_value is not an array.
|
||||
if (!is_array($default_value)) {
|
||||
return [$type => [], 'other' => NULL];
|
||||
}
|
||||
|
||||
$default_options = array_combine($default_value, $default_value);
|
||||
$flattened_options = OptGroup::flattenOptions($element['#options']);
|
||||
if ($other_options = array_diff_key($default_options, $flattened_options)) {
|
||||
return [
|
||||
$type => array_diff_key($default_options, $other_options) + [static::OTHER_OPTION => static::OTHER_OPTION],
|
||||
'other' => implode($element['#other__option_delimiter'], $other_options),
|
||||
];
|
||||
}
|
||||
|
||||
return [$type => $default_options, 'other' => NULL];
|
||||
}
|
||||
else {
|
||||
if (!empty($default_value) && !WebformOptionsHelper::hasOption($default_value, $element['#options'])) {
|
||||
return [$type => static::OTHER_OPTION, 'other' => $default_value];
|
||||
}
|
||||
|
||||
return [$type => $default_value, 'other' => NULL];
|
||||
}
|
||||
}
|
||||
|
||||
/****************************************************************************/
|
||||
// Error functions.
|
||||
/****************************************************************************/
|
||||
|
||||
/**
|
||||
* Set element required error.
|
||||
*
|
||||
* @param array $element
|
||||
* The webform element.
|
||||
* @param \Drupal\Core\Form\FormStateInterface $form_state
|
||||
* The current state of the form.
|
||||
*/
|
||||
protected static function setElementError(array &$element, FormStateInterface $form_state) {
|
||||
if (isset($element['#required_error'])) {
|
||||
$form_state->setError($element, $element['#required_error']);
|
||||
}
|
||||
elseif (isset($element['#title'])) {
|
||||
$form_state->setError($element, t('@name field is required.', ['@name' => $element['#title']]));
|
||||
}
|
||||
else {
|
||||
$form_state->setError($element);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set element required error.
|
||||
*
|
||||
* @param array $element
|
||||
* The webform element.
|
||||
* @param \Drupal\Core\Form\FormStateInterface $form_state
|
||||
* The current state of the form.
|
||||
*/
|
||||
protected static function setOtherError(array &$element, FormStateInterface $form_state) {
|
||||
if (isset($element['#required_error'])) {
|
||||
$form_state->setError($element['other'], $element['#required_error']);
|
||||
}
|
||||
elseif (isset($element['#title'])) {
|
||||
$form_state->setError($element['other'], t('@name field is required.', ['@name' => $element['#title']]));
|
||||
}
|
||||
else {
|
||||
$form_state->setError($element['other']);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\webform\Element;
|
||||
|
||||
/**
|
||||
* Provides a webform element for radio buttons with an other option.
|
||||
*
|
||||
* @FormElement("webform_radios_other")
|
||||
*/
|
||||
class WebformRadiosOther extends WebformOtherBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $type = 'radios';
|
||||
|
||||
}
|
||||
126
web/modules/contrib/webform/src/Element/WebformRating.php
Normal file
126
web/modules/contrib/webform/src/Element/WebformRating.php
Normal file
|
|
@ -0,0 +1,126 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\webform\Element;
|
||||
|
||||
use Drupal\Core\Render\Element\Range;
|
||||
use Drupal\Core\Render\Element;
|
||||
|
||||
/**
|
||||
* Provides a webform element for entering a rating.
|
||||
*
|
||||
* @FormElement("webform_rating")
|
||||
*/
|
||||
class WebformRating extends Range {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getInfo() {
|
||||
$class = get_class($this);
|
||||
return [
|
||||
'#min' => 0,
|
||||
'#max' => 5,
|
||||
'#step' => 1,
|
||||
'#star_size' => 'medium',
|
||||
'#reset' => FALSE,
|
||||
'#pre_render' => [
|
||||
[$class, 'preRenderWebformRating'],
|
||||
],
|
||||
'#theme' => 'input__webform_rating',
|
||||
] + parent::getInfo();
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepares a #type 'webform_rating' render element for input.html.twig.
|
||||
*
|
||||
* @param array $element
|
||||
* An associative array containing the properties of the element.
|
||||
* Properties used: #title, #value, #description, #min, #max, #attributes,
|
||||
* #step.
|
||||
*
|
||||
* @return array
|
||||
* The $element with prepared variables ready for input.html.twig.
|
||||
*/
|
||||
public static function preRenderWebformRating(array $element) {
|
||||
$element['#attributes']['type'] = 'range';
|
||||
Element::setAttributes($element, ['id', 'name', 'value', 'step', 'min', 'max']);
|
||||
static::setAttributes($element, ['form-webform-rating']);
|
||||
|
||||
// If value is an empty string set it the min.
|
||||
if ($element['#attributes']['value'] == '') {
|
||||
$element['#attributes']['value'] = $element['#attributes']['min'];
|
||||
}
|
||||
|
||||
$element['#children']['rateit'] = self::buildRateIt($element);
|
||||
|
||||
return $element;
|
||||
}
|
||||
|
||||
/**
|
||||
* Build RateIt div.
|
||||
*
|
||||
* @param array $element
|
||||
* A rating element.
|
||||
*
|
||||
* @return string
|
||||
* The RateIt div tag.
|
||||
*
|
||||
* @see https://github.com/gjunge/rateit.js/wiki
|
||||
*/
|
||||
public static function buildRateIt(array $element) {
|
||||
// Add default properties since this element does not have to be a render
|
||||
// element.
|
||||
// @see \Drupal\webform\Plugin\WebformElement\WebformRating::formatHtml
|
||||
$element += [
|
||||
'#min' => 0,
|
||||
'#max' => 5,
|
||||
'#step' => 1,
|
||||
'#star_size' => 'medium',
|
||||
'#reset' => FALSE,
|
||||
];
|
||||
$is_readonly = (!empty($element['#readonly']) || !empty($element['#attributes']['readonly']));
|
||||
|
||||
$attributes = [
|
||||
'class' => ['rateit', 'svg'],
|
||||
'data-rateit-min' => $element['#min'],
|
||||
'data-rateit-max' => $element['#max'],
|
||||
'data-rateit-step' => $element['#step'],
|
||||
'data-rateit-resetable' => (!$is_readonly && $element['#reset']) ? 'true' : 'false',
|
||||
'data-rateit-readonly' => $is_readonly ? 'true' : 'false',
|
||||
];
|
||||
|
||||
// Set range element's #id.
|
||||
if (isset($element['#id'])) {
|
||||
$attributes['data-rateit-backingfld'] = '#' . $element['#id'];
|
||||
}
|
||||
|
||||
// Set value for HTML preview.
|
||||
// @see \Drupal\webform\Plugin\WebformElement\WebformRating::formatHtml
|
||||
if (isset($element['#value'])) {
|
||||
$attributes['data-rateit-value'] = $element['#value'];
|
||||
}
|
||||
|
||||
if (isset($element['#starwidth']) && isset($element['#starheight'])) {
|
||||
$attributes['data-rateit-starwidth'] = $element['#starwidth'];
|
||||
$attributes['data-rateit-starheight'] = $element['#starheight'];
|
||||
}
|
||||
else {
|
||||
// Set star width and height using the #star_size.
|
||||
$sizes = ['large' => 32, 'medium' => 24, 'small' => 16];
|
||||
$size = (isset($sizes[$element['#star_size']])) ? $element['#star_size'] : 'small';
|
||||
$attributes['data-rateit-starwidth'] = $attributes['data-rateit-starheight'] = $sizes[$size];
|
||||
$attributes['class'][] = 'rateit-' . $size;
|
||||
}
|
||||
|
||||
return [
|
||||
'#type' => 'html_tag',
|
||||
'#tag' => 'div',
|
||||
'#attributes' => $attributes,
|
||||
'#attached' => [
|
||||
'library' => ['webform/webform.element.rating'],
|
||||
],
|
||||
];
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
52
web/modules/contrib/webform/src/Element/WebformRoles.php
Normal file
52
web/modules/contrib/webform/src/Element/WebformRoles.php
Normal file
|
|
@ -0,0 +1,52 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\webform\Element;
|
||||
|
||||
use Drupal\Core\Form\FormStateInterface;
|
||||
use Drupal\Core\Render\Element\Checkboxes;
|
||||
|
||||
/**
|
||||
* Provides a roles entity reference webform element.
|
||||
*
|
||||
* @FormElement("webform_roles")
|
||||
*/
|
||||
class WebformRoles extends Checkboxes {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getInfo() {
|
||||
$info = parent::getInfo();
|
||||
$class = get_class($this);
|
||||
$info['#element_validate'] = [
|
||||
[$class, 'validateWebformRoles'],
|
||||
];
|
||||
$info['#include_anonymous'] = TRUE;
|
||||
return $info;
|
||||
}
|
||||
|
||||
/**
|
||||
* Processes a checkboxes webform element.
|
||||
*/
|
||||
public static function processCheckboxes(&$element, FormStateInterface $form_state, &$complete_form) {
|
||||
$element['#options'] = array_map('\Drupal\Component\Utility\Html::escape', user_role_names());
|
||||
|
||||
// Check if anonymous is included.
|
||||
if (empty($element['#include_anonymous'])) {
|
||||
unset($element['#options']['anonymous']);
|
||||
}
|
||||
|
||||
$element['#attached']['library'][] = 'webform/webform.element.roles';
|
||||
$element['#attributes']['class'][] = 'js-webform-roles-role';
|
||||
return parent::processCheckboxes($element, $form_state, $complete_form);
|
||||
}
|
||||
|
||||
/**
|
||||
* Webform element validation handler for webform_users elements.
|
||||
*/
|
||||
public static function validateWebformRoles(&$element, FormStateInterface $form_state, &$complete_form) {
|
||||
$value = $form_state->getValue($element['#parents'], []);
|
||||
$form_state->setValueForElement($element, array_values(array_filter($value)));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,34 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\webform\Element;
|
||||
|
||||
/**
|
||||
* Provides a webform element for a select menu with an other option.
|
||||
*
|
||||
* See #empty_option and #empty_value for an explanation of various settings for
|
||||
* a select element, including behavior if #required is TRUE or FALSE.
|
||||
*
|
||||
* @FormElement("webform_select_other")
|
||||
*/
|
||||
class WebformSelectOther extends WebformOtherBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $type = 'select';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $properties = [
|
||||
'#required',
|
||||
'#options',
|
||||
'#default_value',
|
||||
'#attributes',
|
||||
|
||||
'#multiple',
|
||||
'#empty_value',
|
||||
'#empty_option',
|
||||
];
|
||||
|
||||
}
|
||||
68
web/modules/contrib/webform/src/Element/WebformSignature.php
Normal file
68
web/modules/contrib/webform/src/Element/WebformSignature.php
Normal file
|
|
@ -0,0 +1,68 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\webform\Element;
|
||||
|
||||
use Drupal\Core\Render\Element\FormElement;
|
||||
use Drupal\Core\Render\Element;
|
||||
|
||||
/**
|
||||
* Provides a webform element for entering a signature.
|
||||
*
|
||||
* @FormElement("webform_signature")
|
||||
*/
|
||||
class WebformSignature extends FormElement {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getInfo() {
|
||||
$class = get_class($this);
|
||||
return [
|
||||
'#input' => TRUE,
|
||||
'#process' => [
|
||||
[$class, 'processAjaxForm'],
|
||||
[$class, 'processGroup'],
|
||||
],
|
||||
'#pre_render' => [
|
||||
[$class, 'preRenderWebformSignature'],
|
||||
],
|
||||
'#theme' => 'input__webform_signature',
|
||||
'#theme_wrappers' => ['form_element'],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepares a #type 'webform_signature' render element for input.html.twig.
|
||||
*
|
||||
* @param array $element
|
||||
* An associative array containing the properties of the element.
|
||||
* Properties used: #title, #value, #description, #min, #max, #attributes,
|
||||
* #step.
|
||||
*
|
||||
* @return array
|
||||
* The $element with prepared variables ready for input.html.twig.
|
||||
*/
|
||||
public static function preRenderWebformSignature(array $element) {
|
||||
$element['#attributes']['type'] = 'hidden';
|
||||
Element::setAttributes($element, ['name', 'value']);
|
||||
static::setAttributes($element, ['js-webform-signature', 'form-webform-signature']);
|
||||
|
||||
$build = [
|
||||
'#prefix' => '<div class="js-webform-signature-pad webform-signature-pad">',
|
||||
'#suffix' => '</div>',
|
||||
];
|
||||
$build['reset'] = [
|
||||
'#type' => 'button',
|
||||
'#value' => t('Reset'),
|
||||
];
|
||||
$build['canvas'] = [
|
||||
'#type' => 'html_tag',
|
||||
'#tag' => 'canvas',
|
||||
];
|
||||
$element['#children'] = $build;
|
||||
|
||||
$element['#attached']['library'][] = 'webform/webform.element.signature';
|
||||
return $element;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,284 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\webform\Element;
|
||||
|
||||
use Drupal\Core\Form\FormStateInterface;
|
||||
use Drupal\Core\Render\Element;
|
||||
use Drupal\Core\Render\Element\Table;
|
||||
use Drupal\Core\StringTranslation\TranslatableMarkup;
|
||||
|
||||
/**
|
||||
* Provides a webform element for a sortable tableselect element.
|
||||
*
|
||||
* @FormElement("webform_tableselect_sort")
|
||||
*/
|
||||
class WebformTableSelectSort extends Table {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getInfo() {
|
||||
$class = get_class($this);
|
||||
return [
|
||||
'#input' => TRUE,
|
||||
'#js_select' => TRUE,
|
||||
'#responsive' => TRUE,
|
||||
'#sticky' => FALSE,
|
||||
'#pre_render' => [
|
||||
[$class, 'preRenderTable'],
|
||||
[$class, 'preRenderWebformTableSelectSort'],
|
||||
],
|
||||
'#process' => [
|
||||
[$class, 'processWebformTableSelectSort'],
|
||||
],
|
||||
'#options' => [],
|
||||
'#empty' => '',
|
||||
'#theme' => 'table__tableselect_sort',
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function valueCallback(&$element, $input, FormStateInterface $form_state) {
|
||||
if ($input === FALSE) {
|
||||
$value = [];
|
||||
$element += ['#default_value' => []];
|
||||
foreach ($element['#default_value'] as $key => $flag) {
|
||||
if ($flag) {
|
||||
$value[$key] = $key;
|
||||
}
|
||||
}
|
||||
return $value;
|
||||
}
|
||||
else {
|
||||
if (is_array($input)) {
|
||||
uasort($input, ['Drupal\Component\Utility\SortArray', 'sortByWeightElement']);
|
||||
$values = [];
|
||||
foreach ($input as $key => $item) {
|
||||
if (!empty($item['checkbox'])) {
|
||||
$values[$item['checkbox']] = $item['checkbox'];
|
||||
}
|
||||
}
|
||||
return $values;
|
||||
}
|
||||
else {
|
||||
return [];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepares a 'webform_tableselect_sort' #type element for rendering.
|
||||
*
|
||||
* @return array
|
||||
* The processed element.
|
||||
*/
|
||||
public static function preRenderWebformTableSelectSort($element) {
|
||||
$rows = [];
|
||||
$header = $element['#header'];
|
||||
|
||||
if (!empty($element['#options'])) {
|
||||
// Generate a table row for each selectable item in #options.
|
||||
foreach (Element::children($element) as $key) {
|
||||
$row = [];
|
||||
|
||||
$row['data'] = [];
|
||||
|
||||
// Set the row to be draggable.
|
||||
$row['class'] = ['draggable'];
|
||||
if (isset($element['#options'][$key]['#attributes'])) {
|
||||
$row += $element['#options'][$key]['#attributes'];
|
||||
}
|
||||
|
||||
// Render the checkbox element.
|
||||
$row['data'][] = \Drupal::service('renderer')->render($element[$key]['checkbox']);
|
||||
|
||||
// As table.html.twig only maps header and row columns by order, create
|
||||
// the correct order by iterating over the header fields.
|
||||
foreach ($element['#header'] as $fieldname => $title) {
|
||||
// A row cell can span over multiple headers, which means less row
|
||||
// cells than headers could be present.
|
||||
if (isset($element['#options'][$key][$fieldname])) {
|
||||
// A header can span over multiple cells and in this case the cells
|
||||
// are passed in an array. The order of this array determines the
|
||||
// order in which they are added.
|
||||
if (is_array($element['#options'][$key][$fieldname]) && !isset($element['#options'][$key][$fieldname]['data'])) {
|
||||
foreach ($element['#options'][$key][$fieldname] as $cell) {
|
||||
$row['data'][] = $cell;
|
||||
}
|
||||
}
|
||||
else {
|
||||
$row['data'][] = $element['#options'][$key][$fieldname];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Render the weight element.
|
||||
$row['data'][] = \Drupal::service('renderer')->render($element[$key]['weight']);
|
||||
|
||||
$rows[] = $row;
|
||||
}
|
||||
// Add an empty header or a "Select all" checkbox to provide room for the
|
||||
// checkboxes in the first table column.
|
||||
if ($element['#js_select']) {
|
||||
// Add a "Select all" checkbox.
|
||||
$element['#attached']['library'][] = 'core/drupal.tableselect';
|
||||
array_unshift($header, ['class' => ['select-all']]);
|
||||
}
|
||||
else {
|
||||
// Add an empty header when radio buttons are displayed or a "Select all"
|
||||
// checkbox is not desired.
|
||||
array_unshift($header, '');
|
||||
}
|
||||
}
|
||||
|
||||
// Append weight to header.
|
||||
$header[] = t('Weight');
|
||||
|
||||
// Set header and rows.
|
||||
$element['#header'] = $header;
|
||||
$element['#rows'] = $rows;
|
||||
|
||||
// Attach table sort.
|
||||
$element['#attributes']['class'][] = 'js-tableselect-sort';
|
||||
$element['#attributes']['class'][] = 'tableselect-sort';
|
||||
$element['#attached']['library'][] = 'webform/webform.element.tableselect_sort';
|
||||
|
||||
return $element;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates checkbox and weights to populate a 'webform_tableselect_order' table.
|
||||
*
|
||||
* @param array $element
|
||||
* An associative array containing the properties and children of the
|
||||
* webform_tableselect_order element.
|
||||
* @param \Drupal\Core\Form\FormStateInterface $form_state
|
||||
* The current state of the form.
|
||||
* @param array $complete_form
|
||||
* The complete webform structure.
|
||||
*
|
||||
* @return array
|
||||
* The processed element.
|
||||
*/
|
||||
public static function processWebformTableSelectSort(&$element, FormStateInterface $form_state, &$complete_form) {
|
||||
$value = is_array($element['#value']) ? $element['#value'] : [];
|
||||
|
||||
// Add validate callback that extracts the associative array of options.
|
||||
if (isset($element['#element_validate'])) {
|
||||
array_unshift($element['#element_validate'], [get_called_class(), 'validateWebformTableSelectOrder']);
|
||||
}
|
||||
else {
|
||||
$element['#element_validate'][] = [get_called_class(), 'validateWebformTableSelectOrder'];
|
||||
}
|
||||
|
||||
$element['#tree'] = TRUE;
|
||||
|
||||
if (count($element['#options']) > 0) {
|
||||
if (!isset($element['#default_value']) || $element['#default_value'] === 0) {
|
||||
$element['#default_value'] = [];
|
||||
}
|
||||
|
||||
// Place checked options first.
|
||||
$options = [];
|
||||
foreach ($value as $checked_option_key) {
|
||||
if (isset($element['#options'][$checked_option_key])) {
|
||||
$options[$checked_option_key] = $element['#options'][$checked_option_key];
|
||||
unset($element['#options'][$checked_option_key]);
|
||||
}
|
||||
}
|
||||
$options += $element['#options'];
|
||||
$element['#options'] = $options;
|
||||
|
||||
// Set delta and default weight.
|
||||
$delta = count($element['#options']);
|
||||
$weight = 0;
|
||||
|
||||
// Create a checkbox and weight for each item in #options in such a way
|
||||
// that the value of the webform_tableselect_order element behaves as if
|
||||
// it had been of type checkboxes with weight.
|
||||
foreach ($element['#options'] as $key => $choice) {
|
||||
// Do not overwrite manually created children.
|
||||
if (!isset($element[$key])) {
|
||||
$checkbox_title = '';
|
||||
$weight_title = '';
|
||||
if (isset($element['#options'][$key]['title']) && is_array($element['#options'][$key]['title'])) {
|
||||
if (!empty($element['#options'][$key]['title']['data']['#title'])) {
|
||||
$checkbox_title = new TranslatableMarkup('Update @title', [
|
||||
'@title' => $element['#options'][$key]['title']['data']['#title'],
|
||||
]);
|
||||
$weight_title = new TranslatableMarkup('Weight for @title', [
|
||||
'@title' => $element['#options'][$key]['title']['data']['#title'],
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
$element[$key]['checkbox'] = [
|
||||
'#type' => 'checkbox',
|
||||
'#title' => $checkbox_title,
|
||||
'#title_display' => 'invisible',
|
||||
'#return_value' => $key,
|
||||
'#default_value' => isset($value[$key]) ? $key : NULL,
|
||||
'#attributes' => $element['#attributes'],
|
||||
'#ajax' => isset($element['#ajax']) ? $element['#ajax'] : NULL,
|
||||
];
|
||||
$element[$key]['weight'] = [
|
||||
'#type' => 'weight',
|
||||
'#title' => $weight_title,
|
||||
'#title_display' => 'invisible',
|
||||
'#delta' => $delta,
|
||||
'#default_value' => $weight++,
|
||||
'#attributes' => [
|
||||
'class' => ['table-sort-weight'],
|
||||
],
|
||||
];
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
$element['#value'] = [];
|
||||
}
|
||||
|
||||
// Enable tabledrag.
|
||||
$element['#tabledrag'] = [
|
||||
[
|
||||
'action' => 'order',
|
||||
'relationship' => 'sibling',
|
||||
'group' => 'table-sort-weight',
|
||||
],
|
||||
];
|
||||
|
||||
return $element;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates webform_tableselect_other.
|
||||
*/
|
||||
public static function validateWebformTableSelectOrder(&$element, FormStateInterface $form_state, &$complete_form) {
|
||||
// Get and sort checked values.
|
||||
$checked_values = [];
|
||||
foreach (Element::children($element) as $key) {
|
||||
if ($element[$key]['checkbox']['#value']) {
|
||||
$checked_values[] = [
|
||||
'value' => $element[$key]['checkbox']['#value'],
|
||||
'weight' => $element[$key]['weight']['#value'],
|
||||
];
|
||||
}
|
||||
}
|
||||
uasort($checked_values, ['Drupal\Component\Utility\SortArray', 'sortByWeightElement']);
|
||||
|
||||
// Set values.
|
||||
$values = [];
|
||||
foreach ($checked_values as $item) {
|
||||
$values[$item['value']] = $item['value'];
|
||||
}
|
||||
|
||||
// Clear the element's value by setting it to NULL.
|
||||
$form_state->setValueForElement($element, NULL);
|
||||
|
||||
// Now, set the values as the element's value.
|
||||
$form_state->setValueForElement($element, $values);
|
||||
}
|
||||
|
||||
}
|
||||
256
web/modules/contrib/webform/src/Element/WebformTableSort.php
Normal file
256
web/modules/contrib/webform/src/Element/WebformTableSort.php
Normal file
|
|
@ -0,0 +1,256 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\webform\Element;
|
||||
|
||||
use Drupal\Core\Form\FormStateInterface;
|
||||
use Drupal\Core\Render\Element;
|
||||
use Drupal\Core\Render\Element\Table;
|
||||
use Drupal\Core\StringTranslation\TranslatableMarkup;
|
||||
|
||||
/**
|
||||
* Provides a webform element for a sortable table element.
|
||||
*
|
||||
* @FormElement("webform_table_sort")
|
||||
*/
|
||||
class WebformTableSort extends Table {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getInfo() {
|
||||
$class = get_class($this);
|
||||
return [
|
||||
'#input' => TRUE,
|
||||
'#js_select' => TRUE,
|
||||
'#responsive' => TRUE,
|
||||
'#sticky' => FALSE,
|
||||
'#pre_render' => [
|
||||
[$class, 'preRenderTable'],
|
||||
[$class, 'preRenderWebformTableSort'],
|
||||
],
|
||||
'#process' => [
|
||||
[$class, 'processWebformTableSort'],
|
||||
],
|
||||
'#options' => [],
|
||||
'#empty' => '',
|
||||
'#theme' => 'table__table_sort',
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function valueCallback(&$element, $input, FormStateInterface $form_state) {
|
||||
if ($input === FALSE) {
|
||||
$value = [];
|
||||
$element += ['#default_value' => []];
|
||||
foreach ($element['#default_value'] as $key => $flag) {
|
||||
if ($flag) {
|
||||
$value[$key] = $key;
|
||||
}
|
||||
}
|
||||
return $value;
|
||||
}
|
||||
else {
|
||||
if (is_array($input)) {
|
||||
uasort($input, ['Drupal\Component\Utility\SortArray', 'sortByWeightElement']);
|
||||
$values = [];
|
||||
foreach ($input as $key => $item) {
|
||||
if (!empty($item['value'])) {
|
||||
$values[$item['value']] = $item['value'];
|
||||
}
|
||||
}
|
||||
return $values;
|
||||
}
|
||||
else {
|
||||
return [];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepares a 'webform_table_sort' #type element for rendering.
|
||||
*
|
||||
* @return array
|
||||
* The processed element.
|
||||
*/
|
||||
public static function preRenderWebformTableSort($element) {
|
||||
$rows = [];
|
||||
$header = $element['#header'];
|
||||
if (!empty($element['#options'])) {
|
||||
// Generate a table row for each selectable item in #options.
|
||||
foreach (Element::children($element) as $key) {
|
||||
$row = [];
|
||||
|
||||
$row['data'] = [];
|
||||
|
||||
// Set the row to be draggable.
|
||||
$row['class'] = ['draggable'];
|
||||
if (isset($element['#options'][$key]['#attributes'])) {
|
||||
$row += $element['#options'][$key]['#attributes'];
|
||||
}
|
||||
|
||||
// As table.html.twig only maps header and row columns by order, create
|
||||
// the correct order by iterating over the header fields.
|
||||
foreach ($element['#header'] as $fieldname => $title) {
|
||||
// A row cell can span over multiple headers, which means less row
|
||||
// cells than headers could be present.
|
||||
if (isset($element['#options'][$key][$fieldname])) {
|
||||
// A header can span over multiple cells and in this case the cells
|
||||
// are passed in an array. The order of this array determines the
|
||||
// order in which they are added.
|
||||
if (is_array($element['#options'][$key][$fieldname]) && !isset($element['#options'][$key][$fieldname]['data'])) {
|
||||
foreach ($element['#options'][$key][$fieldname] as $cell) {
|
||||
$row['data'][] = $cell;
|
||||
}
|
||||
}
|
||||
else {
|
||||
$row['data'][] = $element['#options'][$key][$fieldname];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Render the weight and hidden value element.
|
||||
$weight = [$element[$key]['weight'], $element[$key]['value']];
|
||||
$row['data'][] = \Drupal::service('renderer')->render($weight);
|
||||
|
||||
$rows[] = $row;
|
||||
}
|
||||
}
|
||||
|
||||
// Append weight to header.
|
||||
$header[] = t('Weight');
|
||||
|
||||
// Set header and rows.
|
||||
$element['#header'] = $header;
|
||||
$element['#rows'] = $rows;
|
||||
|
||||
// Attach table sort.
|
||||
$element['#attributes']['class'][] = 'js-table-sort';
|
||||
$element['#attributes']['class'][] = 'table-sort';
|
||||
|
||||
return $element;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates checkbox and weights to populate a 'webform_table_order' table.
|
||||
*
|
||||
* @param array $element
|
||||
* An associative array containing the properties and children of the
|
||||
* webform_table_order element.
|
||||
* @param \Drupal\Core\Form\FormStateInterface $form_state
|
||||
* The current state of the form.
|
||||
* @param array $complete_form
|
||||
* The complete webform structure.
|
||||
*
|
||||
* @return array
|
||||
* The processed element.
|
||||
*/
|
||||
public static function processWebformTableSort(&$element, FormStateInterface $form_state, &$complete_form) {
|
||||
$value = is_array($element['#value']) ? $element['#value'] : [];
|
||||
|
||||
// Add validate callback that extracts the associative array of options.
|
||||
if (isset($element['#element_validate'])) {
|
||||
array_unshift($element['#element_validate'], [get_called_class(), 'validateWebformTableSelectOrder']);
|
||||
}
|
||||
else {
|
||||
$element['#element_validate'][] = [get_called_class(), 'validateWebformTableSelectOrder'];
|
||||
}
|
||||
|
||||
$element['#tree'] = TRUE;
|
||||
|
||||
if (count($element['#options']) > 0) {
|
||||
if (!isset($element['#default_value']) || $element['#default_value'] === 0) {
|
||||
$element['#default_value'] = [];
|
||||
}
|
||||
|
||||
// Place checked options first.
|
||||
$options = [];
|
||||
foreach ($value as $checked_option_key) {
|
||||
if (isset($element['#options'][$checked_option_key])) {
|
||||
$options[$checked_option_key] = $element['#options'][$checked_option_key];
|
||||
unset($element['#options'][$checked_option_key]);
|
||||
}
|
||||
}
|
||||
$options += $element['#options'];
|
||||
$element['#options'] = $options;
|
||||
|
||||
// Set delta and default weight.
|
||||
$delta = count($element['#options']);
|
||||
$weight = 0;
|
||||
|
||||
foreach ($element['#options'] as $key => $choice) {
|
||||
// Do not overwrite manually created children.
|
||||
if (!isset($element[$key])) {
|
||||
$weight_title = '';
|
||||
if (isset($element['#options'][$key]['title']) && is_array($element['#options'][$key]['title'])) {
|
||||
if (!empty($element['#options'][$key]['title']['data']['#title'])) {
|
||||
$weight_title = new TranslatableMarkup('Weight for @title', [
|
||||
'@title' => $element['#options'][$key]['title']['data']['#title'],
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
$element[$key]['value'] = [
|
||||
'#type' => 'hidden',
|
||||
'#value' => $key,
|
||||
];
|
||||
$element[$key]['weight'] = [
|
||||
'#type' => 'weight',
|
||||
'#title' => $weight_title,
|
||||
'#title_display' => 'invisible',
|
||||
'#delta' => $delta,
|
||||
'#default_value' => $weight++,
|
||||
'#attributes' => [
|
||||
'class' => ['table-sort-weight'],
|
||||
],
|
||||
];
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
$element['#value'] = [];
|
||||
}
|
||||
|
||||
// Enable tabledrag.
|
||||
$element['#tabledrag'] = [
|
||||
[
|
||||
'action' => 'order',
|
||||
'relationship' => 'sibling',
|
||||
'group' => 'table-sort-weight',
|
||||
],
|
||||
];
|
||||
|
||||
return $element;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates webform_table_other.
|
||||
*/
|
||||
public static function validateWebformTableSelectOrder(&$element, FormStateInterface $form_state, &$complete_form) {
|
||||
// Get and sort checked values.
|
||||
$checked_values = [];
|
||||
foreach (Element::children($element) as $key) {
|
||||
if ($element[$key]['value']['#value']) {
|
||||
$checked_values[] = [
|
||||
'value' => $element[$key]['value']['#value'],
|
||||
'weight' => $element[$key]['weight']['#value'],
|
||||
];
|
||||
}
|
||||
}
|
||||
uasort($checked_values, ['Drupal\Component\Utility\SortArray', 'sortByWeightElement']);
|
||||
|
||||
// Set values.
|
||||
$values = [];
|
||||
foreach ($checked_values as $item) {
|
||||
$values[$item['value']] = $item['value'];
|
||||
}
|
||||
|
||||
// Clear the element's value by setting it to NULL.
|
||||
$form_state->setValueForElement($element, NULL);
|
||||
|
||||
// Now, set the values as the element's value.
|
||||
$form_state->setValueForElement($element, $values);
|
||||
}
|
||||
|
||||
}
|
||||
58
web/modules/contrib/webform/src/Element/WebformTelephone.php
Normal file
58
web/modules/contrib/webform/src/Element/WebformTelephone.php
Normal file
|
|
@ -0,0 +1,58 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\webform\Element;
|
||||
|
||||
use Drupal\Core\Form\FormStateInterface;
|
||||
|
||||
/**
|
||||
* Provides a webform element for a telephone element.
|
||||
*
|
||||
* @FormElement("webform_telephone")
|
||||
*/
|
||||
class WebformTelephone extends WebformCompositeBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getInfo() {
|
||||
$info = parent::getInfo();
|
||||
unset($info['#title_display']);
|
||||
return $info;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function getCompositeElements() {
|
||||
$elements = [];
|
||||
$elements['type'] = [
|
||||
'#type' => 'select',
|
||||
'#title' => t('Type'),
|
||||
'#title_display' => 'invisible',
|
||||
'#options' => 'phone_types',
|
||||
'#empty_option' => t('- Type -'),
|
||||
];
|
||||
$elements['phone'] = [
|
||||
'#type' => 'tel',
|
||||
'#title' => t('Phone'),
|
||||
'#title_display' => 'invisible',
|
||||
'#international' => TRUE,
|
||||
];
|
||||
$elements['ext'] = [
|
||||
'#title' => t('Ext:'),
|
||||
'#type' => 'number',
|
||||
'#size' => 5,
|
||||
'#min' => 0,
|
||||
];
|
||||
return $elements;
|
||||
}
|
||||
|
||||
/**
|
||||
* Processes a composite webform element.
|
||||
*/
|
||||
public static function processWebformComposite(&$element, FormStateInterface $form_state, &$complete_form) {
|
||||
$element = parent::processWebformComposite($element, $form_state, $complete_form);
|
||||
$element['#attached']['library'][] = 'webform/webform.element.composite_telephone';
|
||||
return $element;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,85 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\webform\Element;
|
||||
|
||||
use Drupal\Core\Form\FormStateInterface;
|
||||
use Drupal\Core\Render\Element\Select;
|
||||
|
||||
/**
|
||||
* Provides a webform element for a term select menu.
|
||||
*
|
||||
* @FormElement("webform_term_select")
|
||||
*/
|
||||
class WebformTermSelect extends Select {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getInfo() {
|
||||
return [
|
||||
'#vocabulary' => '',
|
||||
'#tree_delimiter' => '-',
|
||||
'#breadcrumb' => FALSE,
|
||||
'#breadcrumb_delimiter' => ' › ',
|
||||
'#tree_delimiter' => '-',
|
||||
] + parent::getInfo();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function processSelect(&$element, FormStateInterface $form_state, &$complete_form) {
|
||||
self::setOptions($element);
|
||||
|
||||
$element = parent::processSelect($element, $form_state, $complete_form);
|
||||
|
||||
// Must convert this element['#type'] to a 'select' to prevent
|
||||
// "Illegal choice %choice in %name element" validation error.
|
||||
// @see \Drupal\Core\Form\FormValidator::performRequiredValidation
|
||||
$element['#type'] = 'select';
|
||||
|
||||
return $element;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function setOptions(array &$element) {
|
||||
if (!empty($element['#options'])) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!\Drupal::moduleHandler()->moduleExists('taxonomy')) {
|
||||
return [];
|
||||
}
|
||||
|
||||
if (empty($element['#vocabulary'])) {
|
||||
$element['#options'] = [];
|
||||
return;
|
||||
}
|
||||
|
||||
/** @var \Drupal\taxonomy\TermStorageInterface $taxonomy_storage */
|
||||
$taxonomy_storage = \Drupal::entityTypeManager()->getStorage('taxonomy_term');
|
||||
$tree = $taxonomy_storage->loadTree($element['#vocabulary']);
|
||||
|
||||
$options = [];
|
||||
if (!empty($element['#breadcrumb'])) {
|
||||
// Build term breadcrumbs.
|
||||
$element += ['#breadcrumb_delimiter' => ' › '];
|
||||
$breadcrumb = [];
|
||||
foreach ($tree as $item) {
|
||||
$breadcrumb[$item->depth] = $item->name;
|
||||
$breadcrumb = array_slice($breadcrumb, 0, $item->depth + 1);
|
||||
$options[$item->tid] = implode($element['#breadcrumb_delimiter'], $breadcrumb);
|
||||
}
|
||||
}
|
||||
else {
|
||||
$element += ['#tree_delimiter' => '-'];
|
||||
// Build hierarchical term tree.
|
||||
foreach ($tree as $item) {
|
||||
$options[$item->tid] = str_repeat($element['#tree_delimiter'], $item->depth) . $item->name;
|
||||
}
|
||||
}
|
||||
$element['#options'] = $options;
|
||||
}
|
||||
}
|
||||
153
web/modules/contrib/webform/src/Element/WebformTime.php
Normal file
153
web/modules/contrib/webform/src/Element/WebformTime.php
Normal file
|
|
@ -0,0 +1,153 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\webform\Element;
|
||||
|
||||
use Drupal\Core\Datetime\Entity\DateFormat;
|
||||
use Drupal\Core\Render\Element;
|
||||
use Drupal\Core\Render\Element\FormElement;
|
||||
use Drupal\Core\Form\FormStateInterface;
|
||||
|
||||
/**
|
||||
* Provides a webform element for time selection.
|
||||
*
|
||||
* @code
|
||||
* $form['time'] = array(
|
||||
* '#type' => 'time',
|
||||
* '#title' => $this->t('Time'),
|
||||
* '#default_value' => '12:00 AM'
|
||||
* );
|
||||
* @endcode
|
||||
*
|
||||
* @FormElement("webform_time")
|
||||
*/
|
||||
class WebformTime extends FormElement {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getInfo() {
|
||||
$class = get_class($this);
|
||||
return [
|
||||
'#input' => TRUE,
|
||||
'#theme' => 'input__time',
|
||||
'#process' => [[$class, 'processWebformTime']],
|
||||
'#pre_render' => [[$class, 'preRenderWebformTime']],
|
||||
'#element_validate' => [[$class, 'validateWebformTime']],
|
||||
'#theme_wrappers' => ['form_element'],
|
||||
'#time_format' => 'H:i',
|
||||
'#size' => 10,
|
||||
'#maxlength' => 10,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function valueCallback(&$element, $input, FormStateInterface $form_state) {
|
||||
if ($input === FALSE) {
|
||||
// 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']));
|
||||
return $element['#default_value'];
|
||||
}
|
||||
}
|
||||
|
||||
return $input;
|
||||
}
|
||||
|
||||
/**
|
||||
* Processes a time webform element.
|
||||
*
|
||||
* @param array $element
|
||||
* The webform element to process. Properties used:
|
||||
* - #time_format: The time format used in PHP formats.
|
||||
* @param \Drupal\Core\Form\FormStateInterface $form_state
|
||||
* The current state of the form.
|
||||
* @param array $complete_form
|
||||
* The complete webform structure.
|
||||
*
|
||||
* @return array
|
||||
* The processed element.
|
||||
*/
|
||||
public static function processWebformTime(&$element, FormStateInterface $form_state, &$complete_form) {
|
||||
// Attach JS support for the time field, if we can determine which time
|
||||
// format should be used.
|
||||
if (!empty($element['#time_format'])) {
|
||||
$element['#attached']['library'][] = 'webform/webform.element.time';
|
||||
$element['#attributes']['data-webform-time-format'] = [$element['#time_format']];
|
||||
}
|
||||
return $element;
|
||||
}
|
||||
|
||||
/**
|
||||
* Webform element validation handler for #type 'webform_time'.
|
||||
*
|
||||
* Note that #required is validated by _form_validate() already.
|
||||
*/
|
||||
public static function validateWebformTime(&$element, FormStateInterface $form_state, &$complete_form) {
|
||||
$has_access = (!isset($element['#access']) || $element['#access'] === TRUE);
|
||||
|
||||
$value = $element['#value'];
|
||||
if ($value === '') {
|
||||
return;
|
||||
}
|
||||
|
||||
$time = strtotime($value);
|
||||
if ($time === FALSE) {
|
||||
if ($has_access) {
|
||||
if (isset($element['#title'])) {
|
||||
$form_state->setError($element, t('%name must be a valid time.', ['%name' => $element['#title']]));
|
||||
}
|
||||
else {
|
||||
$form_state->setError($element);
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
$name = empty($element['#title']) ? $element['#parents'][0] : $element['#title'];
|
||||
$time_format = (!empty($element['#time_format'])) ? $element['#time_format'] : DateFormat::load('html_time')->getPattern();
|
||||
|
||||
// Ensure that the input is greater than the #min property, if set.
|
||||
if ($has_access && isset($element['#min'])) {
|
||||
$min = strtotime($element['#min']);
|
||||
if ($time < $min) {
|
||||
$form_state->setError($element, t('%name must be on or after %min.', [
|
||||
'%name' => $name,
|
||||
'%min' => date($time_format, $min),
|
||||
]));
|
||||
}
|
||||
}
|
||||
|
||||
// Ensure that the input is less than the #max property, if set.
|
||||
if ($has_access && isset($element['#max'])) {
|
||||
$max = strtotime($element['#max']);
|
||||
if ($time > $max) {
|
||||
$form_state->setError($element, t('%name must be on or before %max.', [
|
||||
'%name' => $name,
|
||||
'%max' => date($time_format, $max),
|
||||
]));
|
||||
}
|
||||
}
|
||||
|
||||
$form_state->setValueForElement($element, date('H:i:s', $time));
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds form-specific attributes to a 'date' #type element.
|
||||
*
|
||||
* @param array $element
|
||||
* An associative array containing the properties of the element.
|
||||
*
|
||||
* @return array
|
||||
* The $element with prepared variables ready for #theme 'input__time'.
|
||||
*/
|
||||
public static function preRenderWebformTime(array $element) {
|
||||
$element['#attributes']['type'] = 'time';
|
||||
Element::setAttributes($element, ['id', 'name', 'type', 'value', 'size', 'min', 'max', 'step']);
|
||||
static::setAttributes($element, ['form-time']);
|
||||
return $element;
|
||||
}
|
||||
|
||||
}
|
||||
93
web/modules/contrib/webform/src/Element/WebformToggle.php
Normal file
93
web/modules/contrib/webform/src/Element/WebformToggle.php
Normal file
|
|
@ -0,0 +1,93 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\webform\Element;
|
||||
|
||||
use Drupal\Core\Render\Element\Checkbox;
|
||||
|
||||
/**
|
||||
* Provides a webform element for entering a toggle.
|
||||
*
|
||||
* @FormElement("webform_toggle")
|
||||
*/
|
||||
class WebformToggle extends Checkbox {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getInfo() {
|
||||
return self::getDefaultProperties() + parent::getInfo();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get default properties for a toggle element.
|
||||
*
|
||||
* @return array
|
||||
* An associative array container default properties for a toggle element.
|
||||
*/
|
||||
public static function getDefaultProperties() {
|
||||
return [
|
||||
'#toggle_theme' => 'light',
|
||||
'#toggle_size' => 'medium',
|
||||
'#on_text' => '',
|
||||
'#off_text' => '',
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepares a #type 'checkbox' render element for input.html.twig.
|
||||
*
|
||||
* @param array $element
|
||||
* An associative array containing the properties of the element.
|
||||
* Properties used: #title, #value, #return_value, #description, #required,
|
||||
* #attributes, #checked.
|
||||
*
|
||||
* @return array
|
||||
* The $element with prepared variables ready for input.html.twig.
|
||||
*/
|
||||
public static function preRenderCheckbox($element) {
|
||||
$element = parent::preRenderCheckbox($element);
|
||||
|
||||
$element += [
|
||||
'#toggle_size' => 'medium',
|
||||
'#toggle_theme' => 'light',
|
||||
'#on_text' => '',
|
||||
'#off_text' => '',
|
||||
];
|
||||
|
||||
// Toggle heights.
|
||||
$sizes = ['large' => 36, 'medium' => 24, 'small' => 16];
|
||||
$height = $sizes[$element['#toggle_size']];
|
||||
if (!empty($element['#on_text']) || !empty($element['#off_text'])) {
|
||||
$width = $height * 3;
|
||||
}
|
||||
else {
|
||||
$width = $height * 2;
|
||||
}
|
||||
|
||||
$attributes = [
|
||||
'class' => [
|
||||
'js-webform-toggle',
|
||||
'webform-toggle',
|
||||
'toggle',
|
||||
'toggle-' . $element['#toggle_size'],
|
||||
'toggle-' . $element['#toggle_theme'],
|
||||
],
|
||||
'data-toggle-height' => $height,
|
||||
'data-toggle-width' => $width,
|
||||
'data-toggle-text-on' => $element['#on_text'],
|
||||
'data-toggle-text-off' => $element['#off_text'],
|
||||
];
|
||||
|
||||
$element['#children']['toggles'] = [
|
||||
'#type' => 'html_tag',
|
||||
'#tag' => 'div',
|
||||
'#attributes' => $attributes,
|
||||
'#attached' => [
|
||||
'library' => ['webform/webform.element.toggle'],
|
||||
],
|
||||
];
|
||||
|
||||
return $element;
|
||||
}
|
||||
|
||||
}
|
||||
38
web/modules/contrib/webform/src/Element/WebformToggles.php
Normal file
38
web/modules/contrib/webform/src/Element/WebformToggles.php
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\webform\Element;
|
||||
|
||||
use Drupal\Core\Form\FormStateInterface;
|
||||
use Drupal\Core\Render\Element;
|
||||
use Drupal\Core\Render\Element\Checkboxes;
|
||||
|
||||
/**
|
||||
* Provides a webform element for toggles.
|
||||
*
|
||||
* @FormElement("webform_toggles")
|
||||
*/
|
||||
class WebformToggles extends Checkboxes {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getInfo() {
|
||||
return WebformToggle::getDefaultProperties() + parent::getInfo();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function processCheckboxes(&$element, FormStateInterface $form_state, &$complete_form) {
|
||||
$element = parent::processCheckboxes($element, $form_state, $complete_form);
|
||||
|
||||
// Convert checkboxes to toggle elements.
|
||||
foreach (Element::children($element) as $key) {
|
||||
$element[$key]['#type'] = 'webform_toggle';
|
||||
$element[$key] += array_intersect_key($element, WebformToggle::getDefaultProperties());
|
||||
}
|
||||
|
||||
return $element;
|
||||
}
|
||||
|
||||
}
|
||||
63
web/modules/contrib/webform/src/Element/WebformUsers.php
Normal file
63
web/modules/contrib/webform/src/Element/WebformUsers.php
Normal file
|
|
@ -0,0 +1,63 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\webform\Element;
|
||||
|
||||
use Drupal\Core\Entity\Element\EntityAutocomplete;
|
||||
use Drupal\Core\Entity\EntityInterface;
|
||||
use Drupal\Core\Form\FormStateInterface;
|
||||
use Drupal\user\Entity\User;
|
||||
|
||||
/**
|
||||
* Provides a users entity reference webform element.
|
||||
*
|
||||
* @FormElement("webform_users")
|
||||
*/
|
||||
class WebformUsers extends EntityAutocomplete {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getInfo() {
|
||||
$info = parent::getInfo();
|
||||
$class = get_class($this);
|
||||
|
||||
$info['#target_type'] = 'user';
|
||||
$info['#selection_settings'] = ['include_anonymous' => FALSE];
|
||||
$info['#tags'] = TRUE;
|
||||
$info['#default_value'] = [];
|
||||
$info['#element_validate'] = [
|
||||
[$class, 'validateEntityAutocomplete'],
|
||||
[$class, 'validateWebformUsers'],
|
||||
];
|
||||
return $info;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function valueCallback(&$element, $input, FormStateInterface $form_state) {
|
||||
if ($element['#default_value']) {
|
||||
if (!(reset($element['#default_value']) instanceof EntityInterface)) {
|
||||
$element['#default_value'] = User::loadMultiple($element['#default_value']);
|
||||
}
|
||||
}
|
||||
return parent::valueCallback($element, $input, $form_state);
|
||||
}
|
||||
|
||||
/**
|
||||
* Webform element validation handler for webform_users elements.
|
||||
*/
|
||||
public static function validateWebformUsers(&$element, FormStateInterface $form_state, &$complete_form) {
|
||||
$value = $form_state->getValue($element['#parents'], []);
|
||||
$uids = [];
|
||||
if ($value) {
|
||||
foreach ($value as $item) {
|
||||
if (isset($item)) {
|
||||
$uids[] = $item['target_id'];
|
||||
}
|
||||
}
|
||||
}
|
||||
$form_state->setValueForElement($element, $uids);
|
||||
}
|
||||
|
||||
}
|
||||
17
web/modules/contrib/webform/src/Element/WebformVideoFile.php
Normal file
17
web/modules/contrib/webform/src/Element/WebformVideoFile.php
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\webform\Element;
|
||||
|
||||
/**
|
||||
* Provides a webform element for an 'video_file' element.
|
||||
*
|
||||
* @FormElement("webform_video_file")
|
||||
*/
|
||||
class WebformVideoFile extends WebformManagedFileBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $accept = 'video/*';
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\webform\Element;
|
||||
|
||||
use Drupal\Core\Render\Element\Details;
|
||||
|
||||
/**
|
||||
* Provides a webform element for a webform 'wizard' page.
|
||||
*
|
||||
* A webform 'wizard' page is simply a detail widget that is transformed
|
||||
* into a page via the WebformSubmissionForm handler.
|
||||
*
|
||||
* @FormElement("webform_wizard_page")
|
||||
*/
|
||||
class WebformWizardPage extends Details {
|
||||
|
||||
}
|
||||
1675
web/modules/contrib/webform/src/Entity/Webform.php
Normal file
1675
web/modules/contrib/webform/src/Entity/Webform.php
Normal file
File diff suppressed because it is too large
Load diff
185
web/modules/contrib/webform/src/Entity/WebformOptions.php
Normal file
185
web/modules/contrib/webform/src/Entity/WebformOptions.php
Normal file
|
|
@ -0,0 +1,185 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\webform\Entity;
|
||||
|
||||
use Drupal\Core\Serialization\Yaml;
|
||||
use Drupal\Core\Config\Entity\ConfigEntityBase;
|
||||
use Drupal\Core\Entity\EntityStorageInterface;
|
||||
use Drupal\webform\Utility\WebformOptionsHelper;
|
||||
use Drupal\webform\WebformOptionsInterface;
|
||||
|
||||
/**
|
||||
* Defines the webform options entity.
|
||||
*
|
||||
* @ConfigEntityType(
|
||||
* id = "webform_options",
|
||||
* label = @Translation("Webform options"),
|
||||
* handlers = {
|
||||
* "access" = "Drupal\webform\WebformOptionsAccessControlHandler",
|
||||
* "list_builder" = "Drupal\webform\WebformOptionsListBuilder",
|
||||
* "form" = {
|
||||
* "default" = "Drupal\webform\WebformOptionsForm",
|
||||
* "delete" = "Drupal\Core\Entity\EntityDeleteForm",
|
||||
* }
|
||||
* },
|
||||
* admin_permission = "administer webform",
|
||||
* entity_keys = {
|
||||
* "id" = "id",
|
||||
* "label" = "label",
|
||||
* },
|
||||
* links = {
|
||||
* "add-form" = "/admin/structure/webform/settings/options/add",
|
||||
* "edit-form" = "/admin/structure/webform/settings/options/manage/{webform_options}/edit",
|
||||
* "delete-form" = "/admin/structure/webform/settings/options/manage/{webform_options}/delete",
|
||||
* "collection" = "/admin/structure/webform/settings/options/manage",
|
||||
* },
|
||||
* config_export = {
|
||||
* "id",
|
||||
* "uuid",
|
||||
* "label",
|
||||
* "options",
|
||||
* }
|
||||
* )
|
||||
*/
|
||||
class WebformOptions extends ConfigEntityBase implements WebformOptionsInterface {
|
||||
|
||||
/**
|
||||
* The webform options ID.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $id;
|
||||
|
||||
/**
|
||||
* The webform options UUID.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $uuid;
|
||||
|
||||
/**
|
||||
* The webform options label.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $label;
|
||||
|
||||
/**
|
||||
* The webform options options.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $options;
|
||||
|
||||
/**
|
||||
* The webform options decoded.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $optionsDecoded;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getOptions() {
|
||||
if (!isset($this->optionsDecoded)) {
|
||||
try {
|
||||
$options = Yaml::decode($this->options);
|
||||
// Since YAML supports simple values.
|
||||
$options = (is_array($options)) ? $options : [];
|
||||
}
|
||||
catch (\Exception $exception) {
|
||||
$link = $this->link(t('Edit'), 'edit-form');
|
||||
\Drupal::logger('webform')->notice('%title options are not valid. @message', ['%title' => $this->label(), '@message' => $exception->getMessage(), 'link' => $link]);
|
||||
$options = FALSE;
|
||||
}
|
||||
$this->optionsDecoded = $options;
|
||||
}
|
||||
return $this->optionsDecoded;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function setOptions(array $options) {
|
||||
$this->options = Yaml::encode($options);
|
||||
$this->optionsDecoded = NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function hasAlterHooks() {
|
||||
$hook_name = 'webform_options_' . $this->id() . '_alter';
|
||||
$alter_hooks = \Drupal::moduleHandler()->getImplementations($hook_name);
|
||||
return (count($alter_hooks)) ? TRUE : FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function preSave(EntityStorageInterface $storage) {
|
||||
parent::preSave($storage);
|
||||
|
||||
// If the submitted options match the altered options clear the submission
|
||||
// options.
|
||||
$altered_options = [];
|
||||
$temp_element = [];
|
||||
\Drupal::moduleHandler()->alter('webform_options_' . $this->id(), $altered_options, $temp_element);
|
||||
$altered_options = WebformOptionsHelper::convertOptionsToString($altered_options);
|
||||
if ($altered_options == $this->getOptions()) {
|
||||
$this->options = '';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function postSave(EntityStorageInterface $storage, $update = TRUE) {
|
||||
parent::postSave($storage, $update);
|
||||
|
||||
// Clear cached properties.
|
||||
$this->optionsDecoded = NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function getElementOptions(array $element, $property_name = '#options') {
|
||||
// If element already has #options return them.
|
||||
// NOTE: Only WebformOptions can be altered. If you need to alter an
|
||||
// element's options, @see hook_webform_element_alter().
|
||||
if (is_array($element[$property_name])) {
|
||||
return $element[$property_name];
|
||||
}
|
||||
|
||||
// Return empty options if element does not define an options id.
|
||||
if (empty($element[$property_name]) || !is_string($element[$property_name])) {
|
||||
return [];
|
||||
}
|
||||
|
||||
// If options have been set return them.
|
||||
// This allows dynamic options to be overridden.
|
||||
$id = $element[$property_name];
|
||||
if ($webform_options = WebformOptions::load($id)) {
|
||||
$options = $webform_options->getOptions();
|
||||
}
|
||||
else {
|
||||
$options = [];
|
||||
}
|
||||
|
||||
// Alter options using hook_webform_options_alter()
|
||||
// and/or hook_webform_options_WEBFORM_OPTIONS_ID_alter() hook.
|
||||
// @see webform.api.php
|
||||
\Drupal::moduleHandler()->alter('webform_options_' . $id, $options, $element);
|
||||
\Drupal::moduleHandler()->alter('webform_options', $options, $element, $id);
|
||||
|
||||
// Log empty options.
|
||||
if (empty($options)) {
|
||||
\Drupal::logger('webform')->notice('Options %id do not exist.', ['%id' => $id]);
|
||||
}
|
||||
|
||||
return $options;
|
||||
}
|
||||
|
||||
}
|
||||
699
web/modules/contrib/webform/src/Entity/WebformSubmission.php
Normal file
699
web/modules/contrib/webform/src/Entity/WebformSubmission.php
Normal file
|
|
@ -0,0 +1,699 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\webform\Entity;
|
||||
|
||||
use Drupal\Core\Serialization\Yaml;
|
||||
use Drupal\Component\Utility\Crypt;
|
||||
use Drupal\Core\Entity\EntityStorageInterface;
|
||||
use Drupal\Core\Field\BaseFieldDefinition;
|
||||
use Drupal\Core\Entity\ContentEntityBase;
|
||||
use Drupal\Core\Entity\EntityTypeInterface;
|
||||
use Drupal\Core\Entity\EntityChangedTrait;
|
||||
use Drupal\Core\StringTranslation\StringTranslationTrait;
|
||||
use Drupal\user\Entity\User;
|
||||
use Drupal\user\UserInterface;
|
||||
use Drupal\webform\Plugin\Field\FieldType\WebformEntityReferenceItem;
|
||||
use Drupal\webform\WebformInterface;
|
||||
use Drupal\webform\WebformSubmissionInterface;
|
||||
|
||||
/**
|
||||
* Defines the WebformSubmission entity.
|
||||
*
|
||||
* @ingroup webform
|
||||
*
|
||||
* @ContentEntityType(
|
||||
* id = "webform_submission",
|
||||
* label = @Translation("Webform submission"),
|
||||
* bundle_label = @Translation("Webform"),
|
||||
* handlers = {
|
||||
* "storage" = "Drupal\webform\WebformSubmissionStorage",
|
||||
* "storage_schema" = "Drupal\webform\WebformSubmissionStorageSchema",
|
||||
* "views_data" = "Drupal\webform\WebformSubmissionViewsData",
|
||||
* "view_builder" = "Drupal\webform\WebformSubmissionViewBuilder",
|
||||
* "list_builder" = "Drupal\webform\WebformSubmissionListBuilder",
|
||||
* "access" = "Drupal\webform\WebformSubmissionAccessControlHandler",
|
||||
* "form" = {
|
||||
* "default" = "Drupal\webform\WebformSubmissionForm",
|
||||
* "notes" = "Drupal\webform\WebformSubmissionNotesForm",
|
||||
* "duplicate" = "Drupal\webform\WebformSubmissionDuplicateForm",
|
||||
* "delete" = "Drupal\webform\Form\WebformSubmissionDeleteForm",
|
||||
* },
|
||||
* },
|
||||
* bundle_entity_type = "webform",
|
||||
* list_cache_contexts = { "user" },
|
||||
* base_table = "webform_submission",
|
||||
* admin_permission = "administer webform",
|
||||
* entity_keys = {
|
||||
* "id" = "sid",
|
||||
* "bundle" = "webform_id",
|
||||
* "uuid" = "uuid"
|
||||
* },
|
||||
* links = {
|
||||
* "canonical" = "/admin/structure/webform/manage/{webform}/submission/{webform_submission}",
|
||||
* "table" = "/admin/structure/webform/manage/{webform}/submission/{webform_submission}/table",
|
||||
* "text" = "/admin/structure/webform/manage/{webform}/submission/{webform_submission}/text",
|
||||
* "yaml" = "/admin/structure/webform/manage/{webform}/submission/{webform_submission}/yaml",
|
||||
* "edit-form" = "/admin/structure/webform/manage/{webform}/submission/{webform_submission}/edit",
|
||||
* "notes-form" = "/admin/structure/webform/manage/{webform}/submission/{webform_submission}/notes",
|
||||
* "resend-form" = "/admin/structure/webform/manage/{webform}/submission/{webform_submission}/resend",
|
||||
* "duplicate-form" = "/admin/structure/webform/manage/{webform}/submission/{webform_submission}/duplicate",
|
||||
* "delete-form" = "/admin/structure/webform/manage/{webform}/submission/{webform_submission}/delete",
|
||||
* "collection" = "/admin/structure/webform/results/manage/list"
|
||||
* },
|
||||
* permission_granularity = "bundle"
|
||||
* )
|
||||
*/
|
||||
class WebformSubmission extends ContentEntityBase implements WebformSubmissionInterface {
|
||||
|
||||
use EntityChangedTrait;
|
||||
use StringTranslationTrait;
|
||||
|
||||
/**
|
||||
* Store a reference to the current temporary webform.
|
||||
*
|
||||
* @var \Drupal\webform\WebformInterface
|
||||
*
|
||||
* @see \Drupal\webform\WebformEntityElementsValidator::validateRendering()
|
||||
*/
|
||||
protected static $webform;
|
||||
|
||||
/**
|
||||
* The data.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $data = [];
|
||||
|
||||
/**
|
||||
* Reference to original data loaded before any updates.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $originalData = [];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function baseFieldDefinitions(EntityTypeInterface $entity_type) {
|
||||
$fields['serial'] = BaseFieldDefinition::create('integer')
|
||||
->setLabel(t('Serial number'))
|
||||
->setDescription(t('The serial number of the webform submission entity.'))
|
||||
->setReadOnly(TRUE);
|
||||
|
||||
$fields['sid'] = BaseFieldDefinition::create('integer')
|
||||
->setLabel(t('Submission ID'))
|
||||
->setDescription(t('The ID of the webform submission entity.'))
|
||||
->setReadOnly(TRUE);
|
||||
|
||||
$fields['uuid'] = BaseFieldDefinition::create('uuid')
|
||||
->setLabel(t('Submission UUID'))
|
||||
->setDescription(t('The UUID of the webform submission entity.'))
|
||||
->setReadOnly(TRUE);
|
||||
|
||||
$fields['token'] = BaseFieldDefinition::create('string')
|
||||
->setLabel(t('Token'))
|
||||
->setDescription(t('A secure token used to look up a submission.'))
|
||||
->setSetting('max_length', 255)
|
||||
->setReadOnly(TRUE);
|
||||
|
||||
$fields['uri'] = BaseFieldDefinition::create('string')
|
||||
->setLabel(t('Submission URI'))
|
||||
->setDescription(t('The URI the user submitted the webform.'))
|
||||
->setSetting('max_length', 2000)
|
||||
->setReadOnly(TRUE);
|
||||
|
||||
$fields['created'] = BaseFieldDefinition::create('created')
|
||||
->setLabel(t('Created'))
|
||||
->setDescription(t('The time that the webform submission was first saved as draft or submitted.'));
|
||||
|
||||
$fields['completed'] = BaseFieldDefinition::create('timestamp')
|
||||
->setLabel(t('Completed'))
|
||||
->setDescription(t('The time that the webform submission was submitted as complete (not draft).'));
|
||||
|
||||
$fields['changed'] = BaseFieldDefinition::create('changed')
|
||||
->setLabel(t('Changed'))
|
||||
->setDescription(t('The time that the webform submission was last saved (complete or draft).'));
|
||||
|
||||
$fields['in_draft'] = BaseFieldDefinition::create('boolean')
|
||||
->setLabel(t('Is draft'))
|
||||
->setDescription(t('Is this a draft of the submission?'))
|
||||
->setDefaultValue(FALSE);
|
||||
|
||||
$fields['current_page'] = BaseFieldDefinition::create('string')
|
||||
->setLabel(t('Current page'))
|
||||
->setDescription(t('The current wizard page.'))
|
||||
->setSetting('max_length', 128);
|
||||
|
||||
$fields['remote_addr'] = BaseFieldDefinition::create('string')
|
||||
->setLabel(t('Remote IP address'))
|
||||
->setDescription(t('The IP address of the user that submitted the webform.'))
|
||||
->setSetting('max_length', 128);
|
||||
|
||||
$fields['uid'] = BaseFieldDefinition::create('entity_reference')
|
||||
->setLabel(t('Submitted by'))
|
||||
->setDescription(t('The submitter.'))
|
||||
->setSetting('target_type', 'user');
|
||||
|
||||
$fields['langcode'] = BaseFieldDefinition::create('language')
|
||||
->setLabel(t('Language'))
|
||||
->setDescription(t('The submission language code.'));
|
||||
|
||||
$fields['webform_id'] = BaseFieldDefinition::create('entity_reference')
|
||||
->setLabel(t('Webform'))
|
||||
->setDescription(t('The associated webform.'))
|
||||
->setSetting('target_type', 'webform');
|
||||
|
||||
$fields['entity_type'] = BaseFieldDefinition::create('string')
|
||||
->setLabel(t('Submitted to: Entity type'))
|
||||
->setDescription(t('The entity type to which this submission was submitted from.'))
|
||||
->setSetting('is_ascii', TRUE)
|
||||
->setSetting('max_length', EntityTypeInterface::ID_MAX_LENGTH);
|
||||
|
||||
// Can't use entity reference without a target type because it defaults to
|
||||
// an integer which limits reference to only content entities (and not
|
||||
// config entities like Views, Panels, etc...).
|
||||
// @see \Drupal\Core\Field\Plugin\Field\FieldType\EntityReferenceItem::propertyDefinitions()
|
||||
$fields['entity_id'] = BaseFieldDefinition::create('string')
|
||||
->setLabel(t('Submitted to: Entity ID'))
|
||||
->setDescription(t('The ID of the entity of which this webform submission was submitted from.'))
|
||||
->setSetting('max_length', 255);
|
||||
|
||||
$fields['sticky'] = BaseFieldDefinition::create('boolean')
|
||||
->setLabel(t('Sticky'))
|
||||
->setDescription(t('A flag that indicate the status of the webform submission.'))
|
||||
->setDefaultValue(FALSE);
|
||||
|
||||
$fields['notes'] = BaseFieldDefinition::create('string_long')
|
||||
->setLabel(t('Notes'))
|
||||
->setDescription(t('Administrative notes about the webform submission.'))
|
||||
->setDefaultValue('');
|
||||
|
||||
return $fields;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function serial() {
|
||||
return $this->serial->value;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function label() {
|
||||
$t_args = ['@id' => $this->serial()];
|
||||
if ($source_entity = $this->getSourceEntity()) {
|
||||
$t_args['@form'] = $source_entity->label();
|
||||
}
|
||||
else {
|
||||
$t_args['@form'] = $this->getWebform()->label();
|
||||
}
|
||||
return $this->t('@form: Submission #@id', $t_args);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getCreatedTime() {
|
||||
if (isset($this->get('created')->value)) {
|
||||
return $this->get('created')->value;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function setCreatedTime($created) {
|
||||
$this->set('created', $created);
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getChangedTime() {
|
||||
return $this->get('changed')->value;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function setChangedTime($timestamp) {
|
||||
$this->set('changed', $timestamp);
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getCompletedTime() {
|
||||
return $this->get('completed')->value;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function setCompletedTime($timestamp) {
|
||||
$this->set('completed', $timestamp);
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getNotes() {
|
||||
return $this->get('notes')->value;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function setNotes($notes) {
|
||||
$this->set('notes', $notes);
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getSticky() {
|
||||
return $this->get('sticky')->value;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function setSticky($sticky) {
|
||||
$this->set('sticky', $sticky);
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getRemoteAddr() {
|
||||
return $this->get('remote_addr')->value ?: $this->t('(unknown)');
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function setRemoteAddr($ip_address) {
|
||||
$this->set('remote_addr', $ip_address);
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getCurrentPage() {
|
||||
return $this->get('current_page')->value;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function setCurrentPage($current_page) {
|
||||
$this->set('current_page', $current_page);
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getCurrentPageTitle() {
|
||||
$current_page = $this->getCurrentPage();
|
||||
$page = $this->getWebform()->getPage($current_page);
|
||||
return ($page && isset($page['#title'])) ? $page['#title'] : $current_page;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getData($key = NULL) {
|
||||
if (isset($key)) {
|
||||
return (isset($this->data[$key])) ? $this->data[$key] : NULL;
|
||||
}
|
||||
else {
|
||||
return $this->data;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function setData(array $data) {
|
||||
$this->data = $data;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getOriginalData($key = NULL) {
|
||||
if ($key !== NULL) {
|
||||
return (isset($this->originalData[$key])) ? $this->originalData[$key] : NULL;
|
||||
}
|
||||
else {
|
||||
return $this->originalData;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function setOriginalData(array $data) {
|
||||
$this->originalData = $data;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getToken() {
|
||||
return $this->token->value;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getWebform() {
|
||||
if (isset($this->webform_id->entity)) {
|
||||
return $this->webform_id->entity;
|
||||
}
|
||||
else {
|
||||
return self::$webform;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getSourceEntity() {
|
||||
if ($this->entity_type->value && $this->entity_id->value) {
|
||||
$entity_type = $this->entity_type->value;
|
||||
$entity_id = $this->entity_id->value;
|
||||
return $this->entityTypeManager()->getStorage($entity_type)->load($entity_id);
|
||||
}
|
||||
else {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getSourceUrl() {
|
||||
$uri = $this->uri->value;
|
||||
if ($uri !== NULL && ($url = \Drupal::pathValidator()->getUrlIfValid($uri))) {
|
||||
return $url->setOption('absolute', TRUE);
|
||||
}
|
||||
elseif (($entity = $this->getSourceEntity()) && $entity->hasLinkTemplate('canonical')) {
|
||||
return $entity->toUrl()->setOption('absolute', TRUE);
|
||||
}
|
||||
else {
|
||||
return $this->getWebform()->toUrl()->setOption('absolute', TRUE);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getTokenUrl() {
|
||||
return $this->getSourceUrl()
|
||||
->setOption('query', ['token' => $this->token->value]);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function invokeWebformHandlers($method, &$context1 = NULL, &$context2 = NULL) {
|
||||
if ($webform = $this->getWebform()) {
|
||||
$webform->invokeHandlers($method, $this, $context1, $context2);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function invokeWebformElements($method, &$context1 = NULL, &$context2 = NULL) {
|
||||
if ($webform = $this->getWebform()) {
|
||||
$webform->invokeElements($method, $this, $context1, $context2);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getOwner() {
|
||||
$user = $this->get('uid')->entity;
|
||||
if (!$user || $user->isAnonymous()) {
|
||||
$user = User::getAnonymousUser();
|
||||
}
|
||||
return $user;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getOwnerId() {
|
||||
return $this->get('uid')->target_id;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function setOwnerId($uid) {
|
||||
$this->set('uid', $uid);
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function setOwner(UserInterface $account) {
|
||||
$this->set('uid', $account->id());
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function isDraft() {
|
||||
return $this->get('in_draft')->value ? TRUE : FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function isCompleted() {
|
||||
return $this->get('completed')->value ? TRUE : FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function isSticky() {
|
||||
return (bool) $this->get('sticky')->value;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function hasNotes() {
|
||||
return $this->notes ? TRUE : FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Track the state of a submission.
|
||||
*
|
||||
* @return int
|
||||
* Either STATE_NEW, STATE_DRAFT, STATE_COMPLETED, or STATE_UPDATED,
|
||||
* depending on the last save operation performed.
|
||||
*/
|
||||
public function getState() {
|
||||
if (!$this->id()) {
|
||||
return self::STATE_UNSAVED;
|
||||
}
|
||||
elseif ($this->isDraft()) {
|
||||
return self::STATE_DRAFT;
|
||||
}
|
||||
elseif ($this->completed->value == $this->changed->value) {
|
||||
return self::STATE_COMPLETED;
|
||||
}
|
||||
else {
|
||||
return self::STATE_UPDATED;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function urlRouteParameters($rel) {
|
||||
$uri_route_parameters = parent::urlRouteParameters($rel);
|
||||
$uri_route_parameters['webform'] = $this->getWebform()->id();
|
||||
return $uri_route_parameters;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function preCreate(EntityStorageInterface $storage, array &$values) {
|
||||
if (empty($values['webform_id']) && empty($values['webform'])) {
|
||||
if (empty($values['webform_id'])) {
|
||||
throw new \Exception('Webform id (webform_id) is required to create a webform submission.');
|
||||
}
|
||||
elseif (empty($values['webform'])) {
|
||||
throw new \Exception('Webform (webform) is required to create a webform submission.');
|
||||
}
|
||||
}
|
||||
|
||||
// Get temporary webform entity and store it in the static
|
||||
// WebformSubmission::$webform property.
|
||||
// This could be reworked to use \Drupal\user\PrivateTempStoreFactory
|
||||
// but it might be overkill since we are just using this to validate
|
||||
// that a webform's elements can be rendered.
|
||||
// @see \Drupal\webform\WebformEntityElementsValidator::validateRendering()
|
||||
// @see \Drupal\webform_ui\Form\WebformUiElementTestForm::buildForm()
|
||||
if (isset($values['webform']) && ($values['webform'] instanceof WebformInterface)) {
|
||||
$webform = $values['webform'];
|
||||
self::$webform = $values['webform'];
|
||||
$values['webform_id'] = 'temp';
|
||||
}
|
||||
else {
|
||||
/** @var \Drupal\webform\WebformInterface $webform */
|
||||
$webform = Webform::load($values['webform_id']);
|
||||
self::$webform = NULL;
|
||||
}
|
||||
|
||||
// Get request's source entity parameter.
|
||||
/** @var \Drupal\webform\WebformRequestInterface $request_handler */
|
||||
$request_handler = \Drupal::service('webform.request');
|
||||
$source_entity = $request_handler->getCurrentSourceEntity('webform');
|
||||
$values += [
|
||||
'entity_type' => ($source_entity) ? $source_entity->getEntityTypeId() : NULL,
|
||||
'entity_id' => ($source_entity) ? $source_entity->id() : NULL,
|
||||
];
|
||||
|
||||
// Decode all data in an array.
|
||||
if (empty($values['data'])) {
|
||||
$values['data'] = [];
|
||||
}
|
||||
elseif (is_string($values['data'])) {
|
||||
$values['data'] = Yaml::decode($values['data']);
|
||||
}
|
||||
|
||||
// Get default date from source entity 'webform' field.
|
||||
if ($values['entity_type'] && $values['entity_id']) {
|
||||
$source_entity = \Drupal::entityTypeManager()
|
||||
->getStorage($values['entity_type'])
|
||||
->load($values['entity_id']);
|
||||
if ($webform_field_name = WebformEntityReferenceItem::getEntityWebformFieldName($source_entity)) {
|
||||
if ($source_entity->$webform_field_name->target_id == $webform->id() && $source_entity->$webform_field_name->default_data) {
|
||||
$values['data'] += Yaml::decode($source_entity->$webform_field_name->default_data);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Set default uri and remote_addr.
|
||||
$current_request = \Drupal::requestStack()->getCurrentRequest();
|
||||
$values += [
|
||||
'uri' => preg_replace('#^' . base_path() . '#', '/', $current_request->getRequestUri()),
|
||||
'remote_addr' => ($webform && $webform->isConfidential()) ? '' : $current_request->getClientIp(),
|
||||
];
|
||||
|
||||
// Get default uid and langcode.
|
||||
$values += [
|
||||
'uid' => \Drupal::currentUser()->id(),
|
||||
'langcode' => \Drupal::languageManager()->getCurrentLanguage()->getId(),
|
||||
];
|
||||
|
||||
// Hard code the token.
|
||||
$values['token'] = Crypt::randomBytesBase64();
|
||||
|
||||
// Set is draft.
|
||||
$values['in_draft'] = FALSE;
|
||||
|
||||
$webform->invokeHandlers(__FUNCTION__, $values);
|
||||
$webform->invokeElements(__FUNCTION__, $values);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function preSave(EntityStorageInterface $storage) {
|
||||
// Set created.
|
||||
if (!$this->created->value) {
|
||||
$this->created->value = REQUEST_TIME;
|
||||
}
|
||||
|
||||
// Set changed.
|
||||
$this->changed->value = REQUEST_TIME;
|
||||
|
||||
// Set completed.
|
||||
if ($this->isDraft()) {
|
||||
$this->completed->value = NULL;
|
||||
}
|
||||
elseif (!$this->isCompleted()) {
|
||||
$this->completed->value = REQUEST_TIME;
|
||||
}
|
||||
|
||||
parent::preSave($storage);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function save() {
|
||||
// Clear the remote_addr for confidential submissions.
|
||||
if ($this->getWebform()->isConfidential()) {
|
||||
$this->get('remote_addr')->value = '';
|
||||
}
|
||||
|
||||
return parent::save();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function toArray($custom = FALSE, $check_access = FALSE) {
|
||||
if ($custom === FALSE) {
|
||||
return parent::toArray();
|
||||
}
|
||||
else {
|
||||
$values = parent::toArray();
|
||||
foreach ($values as $key => $item) {
|
||||
// Issue #2567899 It seems it is impossible to save an empty string to an entity.
|
||||
// @see https://www.drupal.org/node/2567899
|
||||
// Solution: Set empty (aka NULL) items to an empty string.
|
||||
if (empty($item)) {
|
||||
$values[$key] = '';
|
||||
}
|
||||
else {
|
||||
$value = reset($item);
|
||||
$values[$key] = reset($value);
|
||||
}
|
||||
}
|
||||
|
||||
$values['data'] = $this->getData();
|
||||
|
||||
// Check access.
|
||||
if ($check_access) {
|
||||
// Check field definition access.
|
||||
$submission_storage = \Drupal::entityTypeManager()->getStorage('webform_submission');
|
||||
$field_definitions = $submission_storage->getFieldDefinitions();
|
||||
$field_definitions = $submission_storage->checkFieldDefinitionAccess($this->getWebform(), $field_definitions + ['data' => TRUE]);
|
||||
$values = array_intersect_key($values, $field_definitions);
|
||||
|
||||
// Check element data access.
|
||||
$elements = $this->getWebform()->getElementsInitializedFlattenedAndHasValue('view');
|
||||
$values['data'] = array_intersect_key($values['data'], $elements);
|
||||
}
|
||||
|
||||
return $values;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,833 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\webform\Form;
|
||||
|
||||
use Drupal\Component\Render\FormattableMarkup;
|
||||
use Drupal\Component\Utility\NestedArray;
|
||||
use Drupal\Component\Utility\Xss;
|
||||
use Drupal\Core\Config\ConfigFactoryInterface;
|
||||
use Drupal\Core\Extension\ModuleHandlerInterface;
|
||||
use Drupal\Core\Form\ConfigFormBase;
|
||||
use Drupal\Core\Form\FormState;
|
||||
use Drupal\Core\Form\FormStateInterface;
|
||||
use Drupal\file\Plugin\Field\FieldType\FileItem;
|
||||
use Drupal\webform\Entity\Webform;
|
||||
use Drupal\webform\Utility\WebformArrayHelper;
|
||||
use Drupal\webform\WebformElementManagerInterface;
|
||||
use Drupal\webform\WebformSubmissionExporterInterface;
|
||||
use Drupal\webform\WebformTokenManagerInterface;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
|
||||
/**
|
||||
* Configure webform admin settings for this site.
|
||||
*/
|
||||
class WebformAdminSettingsForm extends ConfigFormBase {
|
||||
|
||||
/**
|
||||
* The module handler.
|
||||
*
|
||||
* @var \Drupal\Core\Extension\ModuleHandlerInterface
|
||||
*/
|
||||
protected $moduleHandler;
|
||||
|
||||
/**
|
||||
* The webform element manager.
|
||||
*
|
||||
* @var \Drupal\webform\WebformElementManagerInterface
|
||||
*/
|
||||
protected $elementManager;
|
||||
|
||||
/**
|
||||
* The webform submission exporter.
|
||||
*
|
||||
* @var \Drupal\webform\WebformSubmissionExporterInterface
|
||||
*/
|
||||
protected $submissionExporter;
|
||||
|
||||
/**
|
||||
* The token manager.
|
||||
*
|
||||
* @var \Drupal\webform\WebformTranslationManagerInterface
|
||||
*/
|
||||
protected $tokenManager;
|
||||
|
||||
/**
|
||||
* An array of element types.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $elementTypes;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getFormId() {
|
||||
return 'webform_admin_settings_form';
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getEditableConfigNames() {
|
||||
return ['webform.settings'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a WebformAdminSettingsForm object.
|
||||
*
|
||||
* @param \Drupal\Core\Config\ConfigFactoryInterface $config_factory
|
||||
* The factory for configuration objects.
|
||||
* @param \Drupal\Core\Extension\ModuleHandlerInterface $third_party_settings_manager
|
||||
* The module handler.
|
||||
* @param \Drupal\webform\WebformElementManagerInterface $element_manager
|
||||
* The webform element manager.
|
||||
* @param \Drupal\webform\WebformSubmissionExporterInterface $submission_exporter
|
||||
* The webform submission exporter.
|
||||
* @param \Drupal\webform\WebformTokenManagerInterface $token_manager
|
||||
* The token manager.
|
||||
*/
|
||||
public function __construct(ConfigFactoryInterface $config_factory, ModuleHandlerInterface $third_party_settings_manager, WebformElementManagerInterface $element_manager, WebformSubmissionExporterInterface $submission_exporter, WebformTokenManagerInterface $token_manager) {
|
||||
parent::__construct($config_factory);
|
||||
$this->moduleHandler = $third_party_settings_manager;
|
||||
$this->elementManager = $element_manager;
|
||||
$this->submissionExporter = $submission_exporter;
|
||||
$this->tokenManager = $token_manager;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function create(ContainerInterface $container) {
|
||||
return new static(
|
||||
$container->get('config.factory'),
|
||||
$container->get('module_handler'),
|
||||
$container->get('plugin.manager.webform.element'),
|
||||
$container->get('webform_submission.exporter'),
|
||||
$container->get('webform.token_manager')
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function buildForm(array $form, FormStateInterface $form_state) {
|
||||
$config = $this->config('webform.settings');
|
||||
$settings = $config->get('settings');
|
||||
$element_plugins = $this->elementManager->getInstances();
|
||||
|
||||
// Page.
|
||||
$form['page'] = [
|
||||
'#type' => 'details',
|
||||
'#title' => $this->t('Page default settings'),
|
||||
'#tree' => TRUE,
|
||||
];
|
||||
$form['page']['default_page_base_path'] = [
|
||||
'#type' => 'textfield',
|
||||
'#title' => $this->t('Default base path for webform URLs'),
|
||||
'#required' => TRUE,
|
||||
'#default_value' => $config->get('settings.default_page_base_path'),
|
||||
];
|
||||
|
||||
// Form.
|
||||
$form['form'] = [
|
||||
'#type' => 'details',
|
||||
'#title' => $this->t('Form default settings'),
|
||||
'#tree' => TRUE,
|
||||
];
|
||||
$form['form']['default_form_closed_message'] = [
|
||||
'#type' => 'webform_html_editor',
|
||||
'#title' => $this->t('Default closed message'),
|
||||
'#required' => TRUE,
|
||||
'#default_value' => $config->get('settings.default_form_closed_message'),
|
||||
];
|
||||
$form['form']['default_form_exception_message'] = [
|
||||
'#type' => 'webform_html_editor',
|
||||
'#title' => $this->t('Default closed exception message'),
|
||||
'#required' => TRUE,
|
||||
'#default_value' => $config->get('settings.default_form_exception_message'),
|
||||
];
|
||||
$form['form']['default_form_confidential_message'] = [
|
||||
'#type' => 'webform_html_editor',
|
||||
'#title' => $this->t('Default confidential message'),
|
||||
'#required' => TRUE,
|
||||
'#default_value' => $config->get('settings.default_form_confidential_message'),
|
||||
];
|
||||
$form['form']['default_form_submit_label'] = [
|
||||
'#type' => 'textfield',
|
||||
'#title' => $this->t('Default submit button label'),
|
||||
'#required' => TRUE,
|
||||
'#size' => 20,
|
||||
'#default_value' => $settings['default_form_submit_label'],
|
||||
];
|
||||
$form['form']['default_form_submit_once'] = [
|
||||
'#type' => 'checkbox',
|
||||
'#title' => $this->t('Prevent duplicate submissions'),
|
||||
'#description' => $this->t('If checked, the submit button will be disabled immediately after is is clicked.'),
|
||||
'#default_value' => $settings['default_form_submit_once'],
|
||||
];
|
||||
$form['form']['default_form_disable_back'] = [
|
||||
'#type' => 'checkbox',
|
||||
'#title' => $this->t('Disable back button for all webforms'),
|
||||
'#description' => $this->t('If checked, users will not be allowed to navigate back to the webform using the browsers back button.'),
|
||||
'#return_value' => TRUE,
|
||||
'#default_value' => $config->get('settings.default_form_disable_back'),
|
||||
];
|
||||
$form['form']['default_form_unsaved'] = [
|
||||
'#type' => 'checkbox',
|
||||
'#title' => $this->t('Warn users about unsaved changes'),
|
||||
'#description' => $this->t('If checked, users will be displayed a warning message when they navigate away from a webform with unsaved changes.'),
|
||||
'#return_value' => TRUE,
|
||||
'#default_value' => $config->get('settings.default_form_unsaved'),
|
||||
];
|
||||
$form['form']['default_form_novalidate'] = [
|
||||
'#type' => 'checkbox',
|
||||
'#title' => $this->t('Disable client-side validation for all webforms'),
|
||||
'#description' => $this->t('If checked, the <a href=":href">novalidate</a> attribute, which disables client-side validation, will be added to all webforms.', [':href' => 'http://www.w3schools.com/tags/att_form_novalidate.asp']),
|
||||
'#return_value' => TRUE,
|
||||
'#default_value' => $config->get('settings.default_form_novalidate'),
|
||||
];
|
||||
$form['form']['default_form_details_toggle'] = [
|
||||
'#type' => 'checkbox',
|
||||
'#title' => $this->t('Display collapse/expand all details link'),
|
||||
'#description' => $this->t('If checked, an expand/collapse all (details) link will be added to all webforms with two or more details elements.'),
|
||||
'#return_value' => TRUE,
|
||||
'#default_value' => $config->get('settings.default_form_details_toggle'),
|
||||
];
|
||||
$form['form']['form_classes'] = [
|
||||
'#type' => 'webform_codemirror',
|
||||
'#title' => $this->t('Webform CSS classes'),
|
||||
'#description' => $this->t('A list of classes that will be provided in the "Webform CSS classes" dropdown. Enter one or more classes on each line. These styles should be available in your theme\'s CSS file.'),
|
||||
'#default_value' => $config->get('settings.form_classes'),
|
||||
];
|
||||
$form['form']['button_classes'] = [
|
||||
'#type' => 'webform_codemirror',
|
||||
'#title' => $this->t('Button CSS classes'),
|
||||
'#description' => $this->t('A list of classes that will be provided in "Button CSS classes" dropdown. Enter one or more classes on each line. These styles should be available in your theme\'s CSS file.'),
|
||||
'#default_value' => $config->get('settings.button_classes'),
|
||||
];
|
||||
|
||||
// Wizard.
|
||||
$form['wizard'] = [
|
||||
'#type' => 'details',
|
||||
'#title' => $this->t('Wizard default settings'),
|
||||
'#tree' => TRUE,
|
||||
];
|
||||
$form['wizard']['default_wizard_prev_button_label'] = [
|
||||
'#type' => 'textfield',
|
||||
'#title' => $this->t('Default wizard previous page button label'),
|
||||
'#required' => TRUE,
|
||||
'#size' => 20,
|
||||
'#default_value' => $settings['default_wizard_prev_button_label'],
|
||||
];
|
||||
$form['wizard']['default_wizard_next_button_label'] = [
|
||||
'#type' => 'textfield',
|
||||
'#title' => $this->t('Default wizard next page button label'),
|
||||
'#required' => TRUE,
|
||||
'#size' => 20,
|
||||
'#default_value' => $settings['default_wizard_next_button_label'],
|
||||
];
|
||||
$form['wizard']['default_wizard_start_label'] = [
|
||||
'#type' => 'textfield',
|
||||
'#title' => $this->t('Default wizard start label'),
|
||||
'#required' => TRUE,
|
||||
'#size' => 20,
|
||||
'#default_value' => $settings['default_wizard_start_label'],
|
||||
];
|
||||
$form['wizard']['default_wizard_complete_label'] = [
|
||||
'#type' => 'textfield',
|
||||
'#title' => $this->t('Default wizard end label'),
|
||||
'#required' => TRUE,
|
||||
'#size' => 20,
|
||||
'#default_value' => $settings['default_wizard_complete_label'],
|
||||
];
|
||||
|
||||
// Preview.
|
||||
$form['preview'] = [
|
||||
'#type' => 'details',
|
||||
'#title' => $this->t('Preview default settings'),
|
||||
'#tree' => TRUE,
|
||||
];
|
||||
$form['preview']['default_preview_next_button_label'] = [
|
||||
'#type' => 'textfield',
|
||||
'#title' => $this->t('Default preview button label'),
|
||||
'#required' => TRUE,
|
||||
'#size' => 20,
|
||||
'#default_value' => $settings['default_preview_next_button_label'],
|
||||
];
|
||||
$form['preview']['default_preview_prev_button_label'] = [
|
||||
'#type' => 'textfield',
|
||||
'#title' => $this->t('Default preview previous page button label'),
|
||||
'#required' => TRUE,
|
||||
'#size' => 20,
|
||||
'#default_value' => $settings['default_preview_prev_button_label'],
|
||||
];
|
||||
$form['preview']['default_preview_message'] = [
|
||||
'#type' => 'webform_html_editor',
|
||||
'#title' => $this->t('Default preview message'),
|
||||
'#required' => TRUE,
|
||||
'#default_value' => $settings['default_preview_message'],
|
||||
];
|
||||
|
||||
// Draft.
|
||||
$form['draft'] = [
|
||||
'#type' => 'details',
|
||||
'#title' => $this->t('Draft default settings'),
|
||||
'#tree' => TRUE,
|
||||
];
|
||||
$form['draft']['default_draft_button_label'] = [
|
||||
'#type' => 'textfield',
|
||||
'#title' => $this->t('Default draft button label'),
|
||||
'#required' => TRUE,
|
||||
'#size' => 20,
|
||||
'#default_value' => $settings['default_draft_button_label'],
|
||||
];
|
||||
$form['draft']['default_draft_saved_message'] = [
|
||||
'#type' => 'webform_html_editor',
|
||||
'#title' => $this->t('Default draft save message'),
|
||||
'#required' => TRUE,
|
||||
'#default_value' => $settings['default_draft_saved_message'],
|
||||
];
|
||||
$form['draft']['default_draft_loaded_message'] = [
|
||||
'#type' => 'webform_html_editor',
|
||||
'#title' => $this->t('Default draft load message'),
|
||||
'#required' => TRUE,
|
||||
'#default_value' => $settings['default_draft_loaded_message'],
|
||||
];
|
||||
|
||||
$form['confirmation'] = [
|
||||
'#type' => 'details',
|
||||
'#title' => $this->t('Confirmation default settings'),
|
||||
'#tree' => TRUE,
|
||||
];
|
||||
$form['confirmation']['default_confirmation_message'] = [
|
||||
'#type' => 'webform_html_editor',
|
||||
'#title' => $this->t('Default confirmation message'),
|
||||
'#required' => TRUE,
|
||||
'#default_value' => $config->get('settings.default_confirmation_message'),
|
||||
];
|
||||
$form['confirmation']['default_confirmation_back_label'] = [
|
||||
'#type' => 'textfield',
|
||||
'#title' => $this->t('Default confirmation back label'),
|
||||
'#required' => TRUE,
|
||||
'#default_value' => $config->get('settings.default_confirmation_back_label'),
|
||||
];
|
||||
$form['confirmation']['confirmation_classes'] = [
|
||||
'#type' => 'webform_codemirror',
|
||||
'#title' => $this->t('Confirmation CSS classes'),
|
||||
'#description' => $this->t('A list of classes that will be provided in the "Confirmation CSS classes" dropdown. Enter one or more classes on each line. These styles should be available in your theme\'s CSS file.'),
|
||||
'#default_value' => $config->get('settings.confirmation_classes'),
|
||||
];
|
||||
$form['confirmation']['confirmation_back_classes'] = [
|
||||
'#type' => 'webform_codemirror',
|
||||
'#title' => $this->t('Confirmation back link CSS classes'),
|
||||
'#description' => $this->t('A list of classes that will be provided in the "Confirmation back link CSS classes" dropdown. Enter one or more classes on each line. These styles should be available in your theme\'s CSS file.'),
|
||||
'#default_value' => $config->get('settings.confirmation_back_classes'),
|
||||
];
|
||||
|
||||
// Limit.
|
||||
$form['limit'] = [
|
||||
'#type' => 'details',
|
||||
'#title' => $this->t('Limit default settings'),
|
||||
'#tree' => TRUE,
|
||||
];
|
||||
$form['limit']['default_limit_total_message'] = [
|
||||
'#type' => 'webform_html_editor',
|
||||
'#title' => $this->t('Default total submissions limit message'),
|
||||
'#required' => TRUE,
|
||||
'#default_value' => $config->get('settings.default_limit_total_message'),
|
||||
];
|
||||
$form['limit']['default_limit_user_message'] = [
|
||||
'#type' => 'webform_html_editor',
|
||||
'#title' => $this->t('Default per user submission limit message'),
|
||||
'#required' => TRUE,
|
||||
'#default_value' => $config->get('settings.default_limit_user_message'),
|
||||
];
|
||||
|
||||
// Assets.
|
||||
$form['assets'] = [
|
||||
'#type' => 'details',
|
||||
'#title' => $this->t('Global Assets (CSS/JavaScript)'),
|
||||
'#tree' => TRUE,
|
||||
];
|
||||
$form['assets']['css'] = [
|
||||
'#type' => 'webform_codemirror',
|
||||
'#mode' => 'css',
|
||||
'#title' => $this->t('CSS'),
|
||||
'#description' => $this->t('Enter custom CSS to be attached to all webforms.'),
|
||||
'#default_value' => $config->get('assets.css'),
|
||||
];
|
||||
$form['assets']['javascript'] = [
|
||||
'#type' => 'webform_codemirror',
|
||||
'#mode' => 'javascript',
|
||||
'#title' => $this->t('JavaScript'),
|
||||
'#description' => $this->t('Enter custom JavaScript to be attached to all webforms.'),
|
||||
'#default_value' => $config->get('assets.javascript'),
|
||||
];
|
||||
|
||||
// Elements.
|
||||
$form['elements'] = [
|
||||
'#type' => 'details',
|
||||
'#title' => $this->t('Element default settings'),
|
||||
'#tree' => TRUE,
|
||||
];
|
||||
$form['elements']['allowed_tags'] = [
|
||||
'#type' => 'webform_radios_other',
|
||||
'#title' => $this->t('Allowed tags'),
|
||||
'#options' => [
|
||||
'admin' => $this->t('Admin tags Excludes: script, iframe, etc...'),
|
||||
'html' => $this->t('HTML tags: Includes only @html_tags.', ['@html_tags' => WebformArrayHelper::toString(Xss::getHtmlTagList())]),
|
||||
],
|
||||
'#other__option_label' => $this->t('Custom tags'),
|
||||
'#other__placeholder' => $this->t('Enter multiple tags delimited using spaces'),
|
||||
'#other__default_value' => implode(' ', Xss::getAdminTagList()),
|
||||
'#other__maxlength' => 1000,
|
||||
'#required' => TRUE,
|
||||
'#description' => $this->t('Allowed tags are applied to any element property that may contain HTML markup. This properties include #title, #description, #field_prefix, and #field_suffix'),
|
||||
'#default_value' => $config->get('elements.allowed_tags'),
|
||||
];
|
||||
$form['elements']['wrapper_classes'] = [
|
||||
'#type' => 'webform_codemirror',
|
||||
'#title' => $this->t('Wrapper CSS classes'),
|
||||
'#description' => $this->t('A list of classes that will be provided in the "Wrapper CSS classes" dropdown. Enter one or more classes on each line. These styles should be available in your theme\'s CSS file.'),
|
||||
'#required' => TRUE,
|
||||
'#default_value' => $config->get('elements.wrapper_classes'),
|
||||
];
|
||||
$form['elements']['classes'] = [
|
||||
'#type' => 'webform_codemirror',
|
||||
'#title' => $this->t('Element CSS classes'),
|
||||
'#description' => $this->t('A list of classes that will be provided in the "Element CSS classes" dropdown. Enter one or more classes on each line. These styles should be available in your theme\'s CSS file.'),
|
||||
'#required' => TRUE,
|
||||
'#default_value' => $config->get('elements.classes'),
|
||||
];
|
||||
$form['elements']['default_description_display'] = [
|
||||
'#type' => 'select',
|
||||
'#title' => $this->t('Default description display'),
|
||||
'#options' => [
|
||||
'' => '',
|
||||
'before' => $this->t('Before'),
|
||||
'after' => $this->t('After'),
|
||||
'invisible' => $this->t('Invisible'),
|
||||
'tooltip' => $this->t('Tooltip'),
|
||||
],
|
||||
'#description' => $this->t('Determines the default placement of the description for all webform elements.'),
|
||||
'#default_value' => $config->get('elements.default_description_display'),
|
||||
];
|
||||
$form['elements']['default_google_maps_api_key'] = [
|
||||
'#type' => 'textfield',
|
||||
'#title' => $this->t('Google Maps API key'),
|
||||
'#description' => $this->t('Google requires users to use a valid API key. Using the <a href="https://console.developers.google.com/apis">Google API Manager</a>, you can enable the <em>Google Maps JavaScript API</em>. That will create (or reuse) a <em>Browser key</em> which you can paste here.'),
|
||||
'#default_value' => $config->get('elements.default_google_maps_api_key'),
|
||||
];
|
||||
|
||||
// (Excluded) Types.
|
||||
$types_header = [
|
||||
'title' => ['data' => $this->t('Title')],
|
||||
'type' => ['data' => $this->t('Type')],
|
||||
];
|
||||
$this->elementTypes = [];
|
||||
$types_options = [];
|
||||
foreach ($element_plugins as $element_id => $element_plugin) {
|
||||
$this->elementTypes[$element_id] = $element_id;
|
||||
$types_options[$element_id] = [
|
||||
'title' => $element_plugin->getPluginLabel(),
|
||||
'type' => $element_plugin->getTypeName(),
|
||||
];
|
||||
}
|
||||
$form['types'] = [
|
||||
'#type' => 'details',
|
||||
'#title' => $this->t('Element types'),
|
||||
'#description' => $this->t('Select available element types'),
|
||||
];
|
||||
$form['types']['excluded_types'] = [
|
||||
'#type' => 'tableselect',
|
||||
'#header' => $types_header,
|
||||
'#options' => $types_options,
|
||||
'#required' => TRUE,
|
||||
'#default_value' => array_diff($this->elementTypes, $config->get('elements.excluded_types')),
|
||||
];
|
||||
|
||||
// File.
|
||||
$form['file'] = [
|
||||
'#type' => 'details',
|
||||
'#title' => $this->t('File upload default settings'),
|
||||
'#tree' => TRUE,
|
||||
];
|
||||
$form['file']['file_public'] = [
|
||||
'#type' => 'checkbox',
|
||||
'#title' => $this->t('Allow files to be uploaded to public file system.'),
|
||||
'#description' => $this->t('Public files upload destination is dangerous for webforms that are available to anonymous and/or untrusted users.') . ' ' .
|
||||
$this->t('For more information see: <a href="@href">DRUPAL-PSA-2016-003</a>', ['@href' => 'https://www.drupal.org/psa-2016-003']),
|
||||
'#return_value' => TRUE,
|
||||
'#default_value' => $config->get('file.file_public'),
|
||||
];
|
||||
$form['file']['default_max_filesize'] = [
|
||||
'#type' => 'textfield',
|
||||
'#title' => $this->t('Default maximum upload size'),
|
||||
'#description' => $this->t('Enter a value like "512" (bytes), "80 KB" (kilobytes) or "50 MB" (megabytes) in order to restrict the allowed file size. If left empty the file sizes will be limited only by PHP\'s maximum post and file upload sizes (current limit <strong>%limit</strong>).', ['%limit' => function_exists('file_upload_max_size') ? format_size(file_upload_max_size()) : $this->t('N/A')]),
|
||||
'#element_validate' => [[get_class($this), 'validateMaxFilesize']],
|
||||
'#size' => 10,
|
||||
'#default_value' => $config->get('file.default_max_filesize'),
|
||||
];
|
||||
$file_types = [
|
||||
'managed_file' => 'file',
|
||||
'audio_file' => 'audio file',
|
||||
'document_file' => 'document file',
|
||||
'image_file' => 'image file',
|
||||
'video_file' => 'video file',
|
||||
];
|
||||
foreach ($file_types as $file_type_name => $file_type_title) {
|
||||
$form['file']["default_{$file_type_name}_extensions"] = [
|
||||
'#type' => 'textfield',
|
||||
'#title' => $this->t('Default allowed @title extensions', ['@title' => $file_type_title]),
|
||||
'#description' => $this->t('Separate extensions with a space and do not include the leading dot.'),
|
||||
'#element_validate' => [[get_class($this), 'validateExtensions']],
|
||||
'#required' => TRUE,
|
||||
'#maxlength' => 256,
|
||||
'#default_value' => $config->get("file.default_{$file_type_name}_extensions"),
|
||||
];
|
||||
}
|
||||
|
||||
// Format.
|
||||
$form['format'] = [
|
||||
'#type' => 'details',
|
||||
'#title' => $this->t('Format default settings'),
|
||||
'#tree' => TRUE,
|
||||
];
|
||||
foreach ($element_plugins as $element_id => $element_plugin) {
|
||||
// Element.
|
||||
$element_plugin_definition = $element_plugin->getPluginDefinition();
|
||||
$element_plugin_label = $element_plugin_definition['label'];
|
||||
$form['format'][$element_id] = [
|
||||
'#type' => 'details',
|
||||
'#title' => new FormattableMarkup('@label (@id)', ['@label' => $element_plugin_label, '@id' => $element_plugin->getTypeName()]),
|
||||
];
|
||||
// Element item format.
|
||||
$item_formats = $element_plugin->getItemFormats();
|
||||
foreach ($item_formats as $format_name => $format_label) {
|
||||
$item_formats[$format_name] = new FormattableMarkup('@label (@name)', ['@label' => $format_label, '@name' => $format_name]);
|
||||
}
|
||||
$item_formats = ['' => '<' . $this->t('Default') . '>'] + $item_formats;
|
||||
$item_default_format = $element_plugin->getItemDefaultFormat();
|
||||
$item_default_format_label = (isset($item_formats[$item_default_format])) ? $item_formats[$item_default_format] : $item_default_format;
|
||||
$form['format'][$element_id]['item'] = [
|
||||
'#type' => 'select',
|
||||
'#title' => $this->t('Item format'),
|
||||
'#description' => $this->t("Select how a @label element's single value is displayed.", ['@label' => $element_plugin_label]) . '<br/>' .
|
||||
$this->t('Defaults to: %value', ['%value' => $item_default_format_label]),
|
||||
'#options' => $item_formats,
|
||||
'#default_value' => $config->get("format.$element_id"),
|
||||
];
|
||||
// Element items format.
|
||||
if ($element_plugin->supportsMultipleValues()) {
|
||||
$items_formats = $element_plugin->getItemsFormats();
|
||||
foreach ($items_formats as $format_name => $format_label) {
|
||||
$items_formats[$format_name] = new FormattableMarkup('@label (@name)', ['@label' => $format_label, '@name' => $format_name]);
|
||||
}
|
||||
$items_formats = ['' => '<' . $this->t('Default') . '>'] + $items_formats;
|
||||
$items_default_format = $element_plugin->getItemsDefaultFormat();
|
||||
$items_default_format_label = (isset($item_formats[$items_default_format])) ? $items_formats[$items_default_format] : $items_default_format;
|
||||
$form['format'][$element_id]['items'] = [
|
||||
'#type' => 'select',
|
||||
'#title' => $this->t('Items format'),
|
||||
'#description' => $this->t("Select how a @label element's multiple values are displayed.", ['@label' => $element_plugin_label]) . '<br/>' .
|
||||
$this->t('Defaults to: %value', ['%value' => $items_default_format_label]),
|
||||
'#options' => $items_formats,
|
||||
'#default_value' => $config->get("format.$element_id"),
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
// Mail.
|
||||
$form['mail'] = [
|
||||
'#type' => 'details',
|
||||
'#title' => $this->t('Email default settings'),
|
||||
'#tree' => TRUE,
|
||||
];
|
||||
$form['mail']['default_from_mail'] = [
|
||||
'#type' => 'textfield',
|
||||
'#title' => $this->t('Default email from address'),
|
||||
'#required' => TRUE,
|
||||
'#default_value' => $config->get('mail.default_from_mail'),
|
||||
];
|
||||
$form['mail']['default_from_name'] = [
|
||||
'#type' => 'textfield',
|
||||
'#title' => $this->t('Default email from name'),
|
||||
'#required' => TRUE,
|
||||
'#default_value' => $config->get('mail.default_from_name'),
|
||||
];
|
||||
$form['mail']['default_subject'] = [
|
||||
'#type' => 'textfield',
|
||||
'#title' => $this->t('Default email subject'),
|
||||
'#required' => TRUE,
|
||||
'#default_value' => $config->get('mail.default_subject'),
|
||||
];
|
||||
$form['mail']['default_body_text'] = [
|
||||
'#type' => 'webform_codemirror',
|
||||
'#mode' => 'text',
|
||||
'#title' => $this->t('Default email body (Plain text)'),
|
||||
'#required' => TRUE,
|
||||
'#default_value' => $config->get('mail.default_body_text'),
|
||||
];
|
||||
$form['mail']['default_body_html'] = [
|
||||
'#type' => 'webform_codemirror',
|
||||
'#mode' => 'html',
|
||||
'#title' => $this->t('Default email body (HTML)'),
|
||||
'#required' => TRUE,
|
||||
'#default_value' => $config->get('mail.default_body_html'),
|
||||
];
|
||||
$form['mail']['token_tree_link'] = $this->tokenManager->buildTreeLink();
|
||||
|
||||
// Export.
|
||||
$form['export'] = [
|
||||
'#type' => 'details',
|
||||
'#title' => $this->t('Export default settings'),
|
||||
];
|
||||
$export_options = NestedArray::mergeDeep($config->get('export') ?: [],
|
||||
$this->submissionExporter->getValuesFromInput($form_state->getUserInput())
|
||||
);
|
||||
$export_form_state = new FormState();
|
||||
$this->submissionExporter->buildExportOptionsForm($form, $export_form_state, $export_options);
|
||||
|
||||
// Batch.
|
||||
$form['batch'] = [
|
||||
'#type' => 'details',
|
||||
'#title' => $this->t('Batch settings'),
|
||||
'#tree' => TRUE,
|
||||
];
|
||||
$form['batch']['default_batch_export_size'] = [
|
||||
'#type' => 'number',
|
||||
'#title' => $this->t('Batch export size'),
|
||||
'#min' => 1,
|
||||
'#required' => TRUE,
|
||||
'#default_value' => $config->get('batch.default_batch_export_size'),
|
||||
];
|
||||
$form['batch']['default_batch_update_size'] = [
|
||||
'#type' => 'number',
|
||||
'#title' => $this->t('Batch update size'),
|
||||
'#min' => 1,
|
||||
'#required' => TRUE,
|
||||
'#default_value' => $config->get('batch.default_batch_update_size'),
|
||||
];
|
||||
$form['batch']['default_batch_delete_size'] = [
|
||||
'#type' => 'number',
|
||||
'#title' => $this->t('Batch delete size'),
|
||||
'#min' => 1,
|
||||
'#required' => TRUE,
|
||||
'#default_value' => $config->get('batch.default_batch_delete_size'),
|
||||
];
|
||||
|
||||
$form['purge_settings'] = [
|
||||
'#type' => 'details',
|
||||
'#title' => $this->t('Automated purging settings'),
|
||||
'#tree' => TRUE,
|
||||
];
|
||||
$form['purge_settings']['cron_size'] = [
|
||||
'#type' => 'number',
|
||||
'#title' => $this->t('Amount of submissions to process'),
|
||||
'#min' => 1,
|
||||
'#default_value' => $config->get('purge_settings.cron_size'),
|
||||
'#description' => $this->t('Amount of submissions to purge during single cron run. You may want to lower this number if you are facing memory or timeout issues when purging via cron.'),
|
||||
];
|
||||
|
||||
// Test.
|
||||
$form['test'] = [
|
||||
'#type' => 'details',
|
||||
'#title' => $this->t('Test settings'),
|
||||
'#tree' => TRUE,
|
||||
];
|
||||
$form['test']['types'] = [
|
||||
'#type' => 'webform_codemirror',
|
||||
'#mode' => 'yaml',
|
||||
'#title' => $this->t('Test data by element type'),
|
||||
'#description' => $this->t("Above test data is keyed by FAPI element #type."),
|
||||
'#default_value' => $config->get('test.types'),
|
||||
];
|
||||
$form['test']['names'] = [
|
||||
'#type' => 'webform_codemirror',
|
||||
'#mode' => 'yaml',
|
||||
'#title' => $this->t('Test data by element name'),
|
||||
'#description' => $this->t("Above test data is keyed by full or partial element names. For example, Using 'zip' will populate fields that are named 'zip' and 'zip_code' but not 'zipcode' or 'zipline'."),
|
||||
'#default_value' => $config->get('test.names'),
|
||||
];
|
||||
|
||||
// UI.
|
||||
$form['ui'] = [
|
||||
'#type' => 'details',
|
||||
'#title' => $this->t('User interface settings'),
|
||||
'#tree' => TRUE,
|
||||
];
|
||||
$form['ui']['video_display'] = [
|
||||
'#type' => 'select',
|
||||
'#title' => $this->t('Video display'),
|
||||
'#description' => $this->t('Controls how videos are displayed in inline help and within the global help section.'),
|
||||
'#options' => [
|
||||
'dialog' => $this->t('Dialog'),
|
||||
'link' => $this->t('External link'),
|
||||
'hidden' => $this->t('Hidden'),
|
||||
],
|
||||
'#default_value' => $config->get('ui.video_display'),
|
||||
];
|
||||
$form['ui']['details_save'] = [
|
||||
'#type' => 'checkbox',
|
||||
'#title' => $this->t('Save details open/close state'),
|
||||
'#description' => $this->t('If checked, all <a href=":details_href">Details</a> element\'s open/close state will be saved using <a href=":local_storage_href">Local Storage</a>.', [
|
||||
':details_href' => 'http://www.w3schools.com/tags/tag_details.asp',
|
||||
':local_storage_href' => 'http://www.w3schools.com/html/html5_webstorage.asp',
|
||||
]),
|
||||
'#return_value' => TRUE,
|
||||
'#default_value' => $config->get('ui.details_save'),
|
||||
];
|
||||
$form['ui']['dialog_disabled'] = [
|
||||
'#type' => 'checkbox',
|
||||
'#title' => $this->t('Disable dialogs'),
|
||||
'#description' => $this->t('If checked, all modal dialogs (ie popups) will be disabled.'),
|
||||
'#return_value' => TRUE,
|
||||
'#default_value' => $config->get('ui.dialog_disabled'),
|
||||
];
|
||||
$form['ui']['offcanvas_disabled'] = [
|
||||
'#type' => 'checkbox',
|
||||
'#title' => $this->t('Disable off-canvas system tray'),
|
||||
'#description' => $this->t('If checked, off-canvas system tray will be disabled.'),
|
||||
'#return_value' => TRUE,
|
||||
'#default_value' => $config->get('ui.offcanvas_disabled'),
|
||||
'#access' => $this->moduleHandler->moduleExists('outside_in') && (floatval(\Drupal::VERSION) >= 8.3),
|
||||
'#states' => [
|
||||
'visible' => [
|
||||
':input[name="ui[dialog_disabled]"]' => [
|
||||
'checked' => FALSE,
|
||||
],
|
||||
],
|
||||
],
|
||||
];
|
||||
if (!$this->moduleHandler->moduleExists('outside_in') && (floatval(\Drupal::VERSION) >= 8.3)) {
|
||||
$form['ui']['offcanvas_message'] = [
|
||||
'#type' => 'webform_message',
|
||||
'#message_type' => 'info',
|
||||
'#message_message' => $this->t('Enable the experimental <a href=":href">System tray module</a> to improve the Webform module\'s user experience.', [':href' => 'https://www.drupal.org/blog/drupal-82-now-with-more-outside-in']),
|
||||
'#states' => [
|
||||
'visible' => [
|
||||
':input[name="ui[dialog_disabled]"]' => [
|
||||
'checked' => FALSE,
|
||||
],
|
||||
],
|
||||
],
|
||||
];
|
||||
}
|
||||
$form['ui']['html_editor_disabled'] = [
|
||||
'#type' => 'checkbox',
|
||||
'#title' => $this->t('Disable HTML editor'),
|
||||
'#description' => $this->t('If checked, all HTML editor will be disabled.'),
|
||||
'#return_value' => TRUE,
|
||||
'#default_value' => $config->get('ui.html_editor_disabled'),
|
||||
];
|
||||
|
||||
// Library.
|
||||
$form['library'] = [
|
||||
'#type' => 'details',
|
||||
'#title' => $this->t('Library settings'),
|
||||
'#tree' => TRUE,
|
||||
];
|
||||
$form['library']['cdn'] = [
|
||||
'#type' => 'checkbox',
|
||||
'#title' => $this->t('Use CDN'),
|
||||
'#description' => $this->t('If checked, all warnings about missing libraries will be disabled.'),
|
||||
'#return_value' => TRUE,
|
||||
'#default_value' => $config->get('library.cdn'),
|
||||
];
|
||||
$form['library']['cdn_message'] = [
|
||||
'#type' => 'webform_message',
|
||||
'#message_type' => 'warning',
|
||||
'#message_message' => $this->t('Note that it is in general not a good idea to load libraries from a CDN; avoid this if possible. It introduces more points of failure both performance- and security-wise, requires more TCP/IP connections to be set up and these external assets are usually not in the browser cache anyway.'),
|
||||
'#states' => [
|
||||
'visible' => [
|
||||
':input[name="library[cdn]"]' => [
|
||||
'checked' => TRUE,
|
||||
],
|
||||
],
|
||||
],
|
||||
];
|
||||
|
||||
return parent::buildForm($form, $form_state);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function submitForm(array &$form, FormStateInterface $form_state) {
|
||||
/* Settings */
|
||||
|
||||
$settings = $form_state->getValue('page')
|
||||
+ $form_state->getValue('form')
|
||||
+ $form_state->getValue('wizard')
|
||||
+ $form_state->getValue('preview')
|
||||
+ $form_state->getValue('draft')
|
||||
+ $form_state->getValue('confirmation')
|
||||
+ $form_state->getValue('limit');
|
||||
|
||||
// Track if we need to trigger an update of all webform paths
|
||||
// because the 'default_page_base_path' changed.
|
||||
$update_paths = ($settings['default_page_base_path'] != $this->config('webform.settings')->get('settings.default_page_base_path')) ? TRUE : FALSE;
|
||||
|
||||
/* Excluded types */
|
||||
|
||||
// Convert list of included types to excluded types.
|
||||
$excluded_types = array_diff($this->elementTypes, array_filter($form_state->getValue('excluded_types')));
|
||||
ksort($excluded_types);
|
||||
|
||||
/* Format */
|
||||
|
||||
$format = $form_state->getValue('format');
|
||||
foreach ($format as $element_id => $element_format) {
|
||||
$format[$element_id] = array_filter($element_format);
|
||||
}
|
||||
$format = array_filter($format);
|
||||
|
||||
/* Config save */
|
||||
|
||||
$config = $this->config('webform.settings');
|
||||
$config->set('settings', $settings);
|
||||
$config->set('assets', $form_state->getValue('assets'));
|
||||
$config->set('elements', $form_state->getValue('elements') + ['excluded_types' => $excluded_types]);
|
||||
$config->set('file', $form_state->getValue('file'));
|
||||
$config->set('format', $format);
|
||||
$config->set('mail', $form_state->getValue('mail'));
|
||||
$config->set('export', $this->submissionExporter->getValuesFromInput($form_state->getValues()));
|
||||
$config->set('batch', $form_state->getValue('batch'));
|
||||
$config->set('purge_settings', $form_state->getValue('purge_settings'));
|
||||
$config->set('test', $form_state->getValue('test'));
|
||||
$config->set('ui', $form_state->getValue('ui'));
|
||||
$config->set('library', $form_state->getValue('library'));
|
||||
$config->save();
|
||||
|
||||
/* Update paths */
|
||||
|
||||
if ($update_paths) {
|
||||
/** @var \Drupal\webform\WebformInterface[] $webforms */
|
||||
$webforms = Webform::loadMultiple();
|
||||
foreach ($webforms as $webform) {
|
||||
$webform->updatePaths();
|
||||
}
|
||||
}
|
||||
|
||||
parent::submitForm($form, $form_state);
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrapper for FileItem::validateExtensions.
|
||||
*/
|
||||
public static function validateExtensions($element, FormStateInterface $form_state) {
|
||||
if (class_exists('\Drupal\file\Plugin\Field\FieldType\FileItem')) {
|
||||
FileItem::validateExtensions($element, $form_state);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrapper for FileItem::validateMaxFilesize.
|
||||
*/
|
||||
public static function validateMaxFilesize($element, FormStateInterface $form_state) {
|
||||
if (class_exists('\Drupal\file\Plugin\Field\FieldType\FileItem')) {
|
||||
FileItem::validateMaxFilesize($element, $form_state);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,79 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\webform\Form;
|
||||
|
||||
use Drupal\Core\Config\ConfigFactoryInterface;
|
||||
use Drupal\Core\Form\ConfigFormBase;
|
||||
use Drupal\Core\Form\FormStateInterface;
|
||||
use Drupal\webform\WebformThirdPartySettingsManagerInterface;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
|
||||
/**
|
||||
* Configure webform third party settings for this site.
|
||||
*/
|
||||
class WebformAdminThirdPartySettingsForm extends ConfigFormBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getFormId() {
|
||||
return 'webform_admin_third_party_settings_form';
|
||||
}
|
||||
|
||||
/**
|
||||
* The webform third party settings manager.
|
||||
*
|
||||
* @var \Drupal\webform\WebformThirdPartySettingsManagerInterface
|
||||
*/
|
||||
protected $thirdPartySettingsManager;
|
||||
|
||||
/**
|
||||
* Constructs a WebformAdminThirdPartySettingsForm object.
|
||||
*
|
||||
* @param \Drupal\Core\Config\ConfigFactoryInterface $config_factory
|
||||
* The factory for configuration objects.
|
||||
* @param \Drupal\webform\WebformThirdPartySettingsManagerInterface $third_party_settings_manager
|
||||
* The webform third party settings manager.
|
||||
*/
|
||||
public function __construct(ConfigFactoryInterface $config_factory, WebformThirdPartySettingsManagerInterface $third_party_settings_manager) {
|
||||
parent::__construct($config_factory);
|
||||
$this->thirdPartySettingsManager = $third_party_settings_manager;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function create(ContainerInterface $container) {
|
||||
return new static(
|
||||
$container->get('config.factory'),
|
||||
$container->get('webform.third_party_settings_manager')
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getEditableConfigNames() {
|
||||
return ['webform.settings'];
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function buildForm(array $form, FormStateInterface $form_state) {
|
||||
$form = $this->thirdPartySettingsManager->buildForm($form, $form_state);
|
||||
return parent::buildForm($form, $form_state);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function submitForm(array &$form, FormStateInterface $form_state) {
|
||||
$config = $this->config('webform.settings');
|
||||
$third_party_settings = $form_state->getValue('third_party_settings') + ($config->get('third_party_settings') ?: []);
|
||||
$config->set('third_party_settings', $third_party_settings);
|
||||
$config->save();
|
||||
parent::submitForm($form, $form_state);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,31 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\webform\Form;
|
||||
|
||||
use Drupal\Core\Form\FormStateInterface;
|
||||
|
||||
/**
|
||||
* Provides the webform filter webform.
|
||||
*/
|
||||
class WebformEntityFilterForm extends WebformFilterFormBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getFormId() {
|
||||
return 'webform_filter_form';
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function buildForm(array $form, FormStateInterface $form_state, $search = NULL, $state = NULL, $state_options = []) {
|
||||
$form = parent::buildForm($form, $form_state, $search, $state, $state_options);
|
||||
$form['filter']['#title'] = $this->t('Filter webforms');
|
||||
$form['filter']['search']['#title'] = $this->t('Filter by title, description, or elements');
|
||||
$form['filter']['search']['#autocomplete_route_name'] = 'entity.webform.autocomplete';
|
||||
$form['filter']['search']['#placeholder'] = $this->t('Filter by title, description, or elements');
|
||||
return $form;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,81 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\webform\Form;
|
||||
|
||||
use Drupal\Core\Form\FormBase;
|
||||
use Drupal\Core\Form\FormStateInterface;
|
||||
|
||||
/**
|
||||
* Provides base class for webform filter webforms.
|
||||
*/
|
||||
abstract class WebformFilterFormBase extends FormBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function buildForm(array $form, FormStateInterface $form_state, $search = NULL, $state = NULL, array $state_options = []) {
|
||||
$form['#attributes'] = ['class' => ['webform-filter-form']];
|
||||
$form['filter'] = [
|
||||
'#type' => 'details',
|
||||
'#title' => $this->t('Filter submissions'),
|
||||
'#open' => TRUE,
|
||||
'#attributes' => ['class' => ['container-inline']],
|
||||
];
|
||||
$form['filter']['search'] = [
|
||||
'#type' => 'search',
|
||||
'#title' => $this->t('Filter by submitted data and/or notes'),
|
||||
'#title_display' => 'invisible',
|
||||
'#placeholder' => $this->t('Filter by submitted data and/or notes'),
|
||||
'#maxlength' => 128,
|
||||
'#size' => 40,
|
||||
'#default_value' => $search,
|
||||
];
|
||||
$form['filter']['state'] = [
|
||||
'#type' => 'select',
|
||||
'#title' => $this->t('State'),
|
||||
'#title_display' => 'invisible',
|
||||
'#options' => $state_options,
|
||||
'#default_value' => $state,
|
||||
];
|
||||
$form['filter']['submit'] = [
|
||||
'#type' => 'submit',
|
||||
'#button_type' => 'primary',
|
||||
'#value' => $this->t('Filter'),
|
||||
];
|
||||
if (!empty($search) || !empty($state)) {
|
||||
$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')),
|
||||
'state' => trim($form_state->getValue('state')),
|
||||
];
|
||||
$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());
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,62 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\webform\Form;
|
||||
|
||||
use Drupal\Core\Form\FormStateInterface;
|
||||
use Drupal\webform\WebformHandlerManagerInterface;
|
||||
use Drupal\webform\WebformInterface;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
|
||||
/**
|
||||
* Provides an add form for webform handler.
|
||||
*/
|
||||
class WebformHandlerAddForm extends WebformHandlerFormBase {
|
||||
|
||||
/**
|
||||
* The webform handler manager.
|
||||
*
|
||||
* @var \Drupal\webform\WebformHandlerManagerInterface
|
||||
*/
|
||||
protected $webformHandlerManager;
|
||||
|
||||
/**
|
||||
* Constructs a WebformHandlerAddForm.
|
||||
*
|
||||
* @param \Drupal\webform\WebformHandlerManagerInterface $webform_handler
|
||||
* The webform handler manager.
|
||||
*/
|
||||
public function __construct(WebformHandlerManagerInterface $webform_handler) {
|
||||
$this->webformHandlerManager = $webform_handler;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function create(ContainerInterface $container) {
|
||||
return new static(
|
||||
$container->get('plugin.manager.webform.handler')
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function buildForm(array $form, FormStateInterface $form_state, WebformInterface $webform = NULL, $webform_handler = NULL) {
|
||||
$form = parent::buildForm($form, $form_state, $webform, $webform_handler);
|
||||
$form['#title'] = $this->t('Add @label handler', ['@label' => $this->webformHandler->label()]);
|
||||
return $form;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function prepareWebformHandler($webform_handler) {
|
||||
$webform_handler = $this->webformHandlerManager->createInstance($webform_handler);
|
||||
// Initialize the handler an pass in the webform.
|
||||
$webform_handler->init($this->webform);
|
||||
// Set the initial weight so this handler comes last.
|
||||
$webform_handler->setWeight(count($this->webform->getHandlers()));
|
||||
return $webform_handler;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,80 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\webform\Form;
|
||||
|
||||
use Drupal\Core\Form\ConfirmFormBase;
|
||||
use Drupal\Core\Form\FormStateInterface;
|
||||
use Drupal\webform\WebformDialogTrait;
|
||||
use Drupal\webform\WebformInterface;
|
||||
|
||||
/**
|
||||
* Form for deleting a webform handler.
|
||||
*/
|
||||
class WebformHandlerDeleteForm extends ConfirmFormBase {
|
||||
|
||||
use WebformDialogTrait;
|
||||
|
||||
/**
|
||||
* The webform containing the webform handler to be deleted.
|
||||
*
|
||||
* @var \Drupal\webform\WebformInterface
|
||||
*/
|
||||
protected $webform;
|
||||
|
||||
/**
|
||||
* The webform handler to be deleted.
|
||||
*
|
||||
* @var \Drupal\webform\WebformHandlerInterface
|
||||
*/
|
||||
protected $webformHandler;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getQuestion() {
|
||||
return $this->t('Are you sure you want to delete the @handler handler from the %webform webform?', ['%webform' => $this->webform->label(), '@handler' => $this->webformHandler->label()]);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getConfirmText() {
|
||||
return $this->t('Delete');
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getCancelUrl() {
|
||||
return $this->webform->toUrl('handlers-form');
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getFormId() {
|
||||
return 'webform_handler_delete_form';
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function buildForm(array $form, FormStateInterface $form_state, WebformInterface $webform = NULL, $webform_handler = NULL) {
|
||||
$this->webform = $webform;
|
||||
$this->webformHandler = $this->webform->getHandler($webform_handler);
|
||||
|
||||
$form = parent::buildForm($form, $form_state);
|
||||
$this->buildConfirmFormDialog($form, $form_state);
|
||||
return $form;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function submitForm(array &$form, FormStateInterface $form_state) {
|
||||
$this->webform->deleteWebformHandler($this->webformHandler);
|
||||
drupal_set_message($this->t('The webform handler %name has been deleted.', ['%name' => $this->webformHandler->label()]));
|
||||
$form_state->setRedirectUrl($this->webform->toUrl('handlers-form'));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,35 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\webform\Form;
|
||||
|
||||
use Drupal\Core\Form\FormStateInterface;
|
||||
use Drupal\webform\WebformInterface;
|
||||
|
||||
/**
|
||||
* Provides a duplicate form for webform handler.
|
||||
*/
|
||||
class WebformHandlerDuplicateForm extends WebformHandlerAddForm {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function buildForm(array $form, FormStateInterface $form_state, WebformInterface $webform = NULL, $webform_handler = NULL) {
|
||||
$form = parent::buildForm($form, $form_state, $webform, $webform_handler);
|
||||
$form['#title'] = $this->t('Duplicate @label handler', ['@label' => $this->webformHandler->label()]);
|
||||
return $form;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function prepareWebformHandler($webform_handler) {
|
||||
$webform_handler = clone $this->webform->getHandler($webform_handler);
|
||||
$webform_handler->setHandlerId(NULL);
|
||||
// Initialize the handler an pass in the webform.
|
||||
$webform_handler->init($this->webform);
|
||||
// Set the initial weight so this handler comes last.
|
||||
$webform_handler->setWeight(count($this->webform->getHandlers()));
|
||||
return $webform_handler;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,29 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\webform\Form;
|
||||
|
||||
use Drupal\Core\Form\FormStateInterface;
|
||||
use Drupal\webform\WebformInterface;
|
||||
|
||||
/**
|
||||
* Provides an edit form for webform handlers.
|
||||
*/
|
||||
class WebformHandlerEditForm extends WebformHandlerFormBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function buildForm(array $form, FormStateInterface $form_state, WebformInterface $webform = NULL, $webform_handler = NULL) {
|
||||
$form = parent::buildForm($form, $form_state, $webform, $webform_handler);
|
||||
$form['#title'] = $this->t('Edit @label handler', ['@label' => $this->webformHandler->label()]);
|
||||
return $form;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function prepareWebformHandler($webform_handler) {
|
||||
return $this->webform->getHandler($webform_handler);
|
||||
}
|
||||
|
||||
}
|
||||
255
web/modules/contrib/webform/src/Form/WebformHandlerFormBase.php
Normal file
255
web/modules/contrib/webform/src/Form/WebformHandlerFormBase.php
Normal file
|
|
@ -0,0 +1,255 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\webform\Form;
|
||||
|
||||
use Drupal\Core\Form\FormBase;
|
||||
use Drupal\Core\Form\FormState;
|
||||
use Drupal\Core\Form\FormStateInterface;
|
||||
use Drupal\Component\Plugin\Exception\PluginNotFoundException;
|
||||
use Drupal\webform\WebformDialogTrait;
|
||||
use Drupal\webform\WebformHandlerInterface;
|
||||
use Drupal\webform\WebformInterface;
|
||||
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
|
||||
|
||||
/**
|
||||
* Provides a base webform for webform handlers.
|
||||
*/
|
||||
abstract class WebformHandlerFormBase extends FormBase {
|
||||
|
||||
use WebformDialogTrait;
|
||||
|
||||
/**
|
||||
* The webform.
|
||||
*
|
||||
* @var \Drupal\webform\WebformInterface
|
||||
*/
|
||||
protected $webform;
|
||||
|
||||
/**
|
||||
* The webform handler.
|
||||
*
|
||||
* @var \Drupal\webform\WebformHandlerInterface
|
||||
*/
|
||||
protected $webformHandler;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getFormId() {
|
||||
return 'webform_handler_form';
|
||||
}
|
||||
|
||||
/**
|
||||
* Form constructor.
|
||||
*
|
||||
* @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.
|
||||
* @param \Drupal\webform\WebformInterface $webform
|
||||
* The webform.
|
||||
* @param string $webform_handler
|
||||
* The webform handler ID.
|
||||
*
|
||||
* @return array
|
||||
* The webform structure.
|
||||
*
|
||||
* @throws \Symfony\Component\HttpKernel\Exception\NotFoundHttpException
|
||||
* Throws not found exception if the number of handler instances for this
|
||||
* webform exceeds the handler's cardinality.
|
||||
*/
|
||||
public function buildForm(array $form, FormStateInterface $form_state, WebformInterface $webform = NULL, $webform_handler = NULL) {
|
||||
$this->webform = $webform;
|
||||
try {
|
||||
$this->webformHandler = $this->prepareWebformHandler($webform_handler);
|
||||
}
|
||||
catch (PluginNotFoundException $e) {
|
||||
throw new NotFoundHttpException("Invalid handler id: '$webform_handler'.");
|
||||
}
|
||||
|
||||
// Limit the number of plugin instanced allowed.
|
||||
if (!$this->webformHandler->getHandlerId()) {
|
||||
$plugin_id = $this->webformHandler->getPluginId();
|
||||
$cardinality = $this->webformHandler->cardinality();
|
||||
$number_of_instances = $webform->getHandlers($plugin_id)->count();
|
||||
if ($cardinality !== WebformHandlerInterface::CARDINALITY_UNLIMITED && $cardinality <= $number_of_instances) {
|
||||
$t_args = ['@number' => $cardinality, '@instances' => $this->formatPlural($cardinality, $this->t('instance is'), $this->t('instances are'))];
|
||||
throw new NotFoundHttpException($this->t('Only @number @instance permitted', $t_args));
|
||||
}
|
||||
}
|
||||
|
||||
$request = $this->getRequest();
|
||||
|
||||
$form['description'] = [
|
||||
'#markup' => $this->webformHandler->description(),
|
||||
'#prefix' => '<p>',
|
||||
'#suffix' => '</p>',
|
||||
];
|
||||
|
||||
$form['id'] = [
|
||||
'#type' => 'value',
|
||||
'#value' => $this->webformHandler->getPluginId(),
|
||||
];
|
||||
|
||||
$form['status'] = [
|
||||
'#type' => 'checkbox',
|
||||
'#title' => $this->t('Enable the %name handler.', ['%name' => $this->webformHandler->label()]),
|
||||
'#default_value' => $this->webformHandler->isEnabled(),
|
||||
// Disable broken plugins.
|
||||
'#disabled' => ($this->webformHandler->getPluginId() == 'broken'),
|
||||
];
|
||||
|
||||
$form['label'] = [
|
||||
'#type' => 'textfield',
|
||||
'#title' => $this->t('Title'),
|
||||
'#maxlength' => 255,
|
||||
'#default_value' => $this->webformHandler->label(),
|
||||
'#required' => TRUE,
|
||||
'#attributes' => ['autofocus' => 'autofocus'],
|
||||
];
|
||||
|
||||
$form['handler_id'] = [
|
||||
'#type' => 'machine_name',
|
||||
'#maxlength' => 64,
|
||||
'#description' => $this->t('A unique name for this handler instance. Must be alpha-numeric and underscore separated.'),
|
||||
'#default_value' => $this->webformHandler->getHandlerId() ?: $this->getUniqueMachineName($this->webformHandler),
|
||||
'#required' => TRUE,
|
||||
'#disabled' => $this->webformHandler->getHandlerId() ? TRUE : FALSE,
|
||||
'#machine_name' => [
|
||||
'exists' => [$this, 'exists'],
|
||||
],
|
||||
];
|
||||
|
||||
$form['settings'] = $this->webformHandler->buildConfigurationForm([], $form_state);
|
||||
// Get $form['settings']['#attributes']['novalidate'] and apply it to the
|
||||
// $form.
|
||||
// This allows handlers with hide/show logic to skip HTML5 validation.
|
||||
// @see http://stackoverflow.com/questions/22148080/an-invalid-form-control-with-name-is-not-focusable
|
||||
if (isset($form['settings']['#attributes']['novalidate'])) {
|
||||
$form['#attributes']['novalidate'] = 'novalidate';
|
||||
}
|
||||
$form['settings']['#tree'] = TRUE;
|
||||
|
||||
// Check the URL for a weight, then the webform handler,
|
||||
// otherwise use default.
|
||||
$form['weight'] = [
|
||||
'#type' => 'hidden',
|
||||
'#value' => $request->query->has('weight') ? (int) $request->query->get('weight') : $this->webformHandler->getWeight(),
|
||||
];
|
||||
|
||||
$form['actions'] = ['#type' => 'actions'];
|
||||
$form['actions']['submit'] = [
|
||||
'#type' => 'submit',
|
||||
'#value' => $this->t('Save'),
|
||||
'#button_type' => 'primary',
|
||||
];
|
||||
|
||||
$form = $this->buildFormDialog($form, $form_state);
|
||||
|
||||
return $form;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function validateForm(array &$form, FormStateInterface $form_state) {
|
||||
// The webform handler configuration is stored in the 'settings' key in
|
||||
// the webform, pass that through for validation.
|
||||
$settings = $form_state->getValue('settings') ?: [];
|
||||
$handler_state = (new FormState())->setValues($settings);
|
||||
$this->webformHandler->validateConfigurationForm($form, $handler_state);
|
||||
|
||||
// Process handler state webform errors.
|
||||
$this->processHandlerFormErrors($handler_state, $form_state);
|
||||
|
||||
// Update the original webform values.
|
||||
$form_state->setValue('settings', $handler_state->getValues());
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function submitForm(array &$form, FormStateInterface $form_state) {
|
||||
if ($response = $this->validateDialog($form, $form_state)) {
|
||||
return $response;
|
||||
}
|
||||
|
||||
$form_state->cleanValues();
|
||||
|
||||
// The webform handler configuration is stored in the 'settings' key in
|
||||
// the webform, pass that through for submission.
|
||||
$handler_data = (new FormState())->setValues($form_state->getValue('settings'));
|
||||
|
||||
$this->webformHandler->submitConfigurationForm($form, $handler_data);
|
||||
// Update the original webform values.
|
||||
$form_state->setValue('settings', $handler_data->getValues());
|
||||
|
||||
$is_new = ($this->webformHandler->getHandlerId()) ? FALSE : TRUE;
|
||||
|
||||
$this->webformHandler->setHandlerId($form_state->getValue('handler_id'));
|
||||
$this->webformHandler->setLabel($form_state->getValue('label'));
|
||||
$this->webformHandler->setStatus($form_state->getValue('status'));
|
||||
$this->webformHandler->setWeight($form_state->getValue('weight'));
|
||||
if ($is_new) {
|
||||
$this->webform->addWebformHandler($this->webformHandler->getConfiguration());
|
||||
}
|
||||
$this->webform->save();
|
||||
|
||||
// Display status message.
|
||||
drupal_set_message($this->t('The webform handler was successfully applied.'));
|
||||
|
||||
// Redirect.
|
||||
return $this->redirectForm($form, $form_state, $this->webform->toUrl('handlers-form'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a unique machine name for a webform handler instance.
|
||||
*
|
||||
* @param \Drupal\webform\WebformHandlerInterface $handler
|
||||
* The webform handler.
|
||||
*
|
||||
* @return string
|
||||
* Returns the unique name.
|
||||
*/
|
||||
public function getUniqueMachineName(WebformHandlerInterface $handler) {
|
||||
$suggestion = $handler->getPluginId();
|
||||
$count = 1;
|
||||
$machine_default = $suggestion;
|
||||
$instance_ids = $this->webform->getHandlers()->getInstanceIds();
|
||||
while (isset($instance_ids[$machine_default])) {
|
||||
$machine_default = $suggestion . '_' . $count++;
|
||||
}
|
||||
// Only return a suggestion if it is not the default plugin id.
|
||||
return ($machine_default != $handler->getPluginId()) ? $machine_default : '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if the webform handler ID already exists.
|
||||
*
|
||||
* @param string $handler_id
|
||||
* The webform handler ID.
|
||||
*
|
||||
* @return bool
|
||||
* TRUE if the webform handler ID exists, FALSE otherwise.
|
||||
*/
|
||||
public function exists($handler_id) {
|
||||
$instance_ids = $this->webform->getHandlers()->getInstanceIds();
|
||||
|
||||
return (isset($instance_ids[$handler_id])) ? TRUE : FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Process handler webform errors in webform.
|
||||
*
|
||||
* @param \Drupal\Core\Form\FormStateInterface $handler_state
|
||||
* The webform handler webform state.
|
||||
* @param \Drupal\Core\Form\FormStateInterface &$form_state
|
||||
* The webform state.
|
||||
*/
|
||||
protected function processHandlerFormErrors(FormStateInterface $handler_state, FormStateInterface &$form_state) {
|
||||
foreach ($handler_state->getErrors() as $name => $message) {
|
||||
$form_state->setErrorByName($name, $message);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,54 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\webform\Form;
|
||||
|
||||
use Drupal\Core\Url;
|
||||
|
||||
/**
|
||||
* Webform for webform results clear webform.
|
||||
*/
|
||||
class WebformResultsClearForm extends WebformSubmissionsDeleteFormBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getFormId() {
|
||||
return 'webform_results_clear';
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getQuestion() {
|
||||
if ($this->sourceEntity) {
|
||||
$t_args = ['%title' => $this->sourceEntity->label()];
|
||||
}
|
||||
else {
|
||||
$t_args = ['%title' => $this->webform->label()];
|
||||
}
|
||||
return $this->t('Are you sure you want to delete all submissions to the %title webform?', $t_args);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getCancelUrl() {
|
||||
$route_name = $this->requestHandler->getRouteName($this->webform, $this->sourceEntity, 'webform.results_submissions');
|
||||
$route_parameters = $this->requestHandler->getRouteParameters($this->webform, $this->sourceEntity);
|
||||
return new Url($route_name, $route_parameters);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getMessage() {
|
||||
if ($this->sourceEntity) {
|
||||
$t_args = ['%title' => $this->sourceEntity->label()];
|
||||
}
|
||||
else {
|
||||
$t_args = ['%title' => $this->webform->label()];
|
||||
}
|
||||
$this->t('Webform %title submissions cleared.', $t_args);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,334 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\webform\Form;
|
||||
|
||||
use Drupal\Core\Form\FormBase;
|
||||
use Drupal\Core\Form\FormStateInterface;
|
||||
use Drupal\webform\WebformRequestInterface;
|
||||
use Drupal\webform\WebformSubmissionStorageInterface;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
|
||||
/**
|
||||
* Webform for webform results custom(ize) webform.
|
||||
*/
|
||||
class WebformResultsCustomForm extends FormBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getFormId() {
|
||||
return 'webform_results_custom';
|
||||
}
|
||||
|
||||
/**
|
||||
* The webform entity.
|
||||
*
|
||||
* @var \Drupal\webform\WebformInterface
|
||||
*/
|
||||
protected $webform;
|
||||
|
||||
/**
|
||||
* The webform source entity.
|
||||
*
|
||||
* @var \Drupal\Core\Entity\EntityInterface
|
||||
*/
|
||||
protected $sourceEntity;
|
||||
|
||||
/**
|
||||
* The webform submission storage.
|
||||
*
|
||||
* @var \Drupal\webform\WebformSubmissionStorageInterface
|
||||
*/
|
||||
protected $submissionStorage;
|
||||
|
||||
/**
|
||||
* Webform request handler.
|
||||
*
|
||||
* @var \Drupal\webform\WebformRequestInterface
|
||||
*/
|
||||
protected $requestHandler;
|
||||
|
||||
/**
|
||||
* Constructs a WebformResultsCustomForm object.
|
||||
*
|
||||
* @param \Drupal\webform\WebformSubmissionStorageInterface $webform_submission_storage
|
||||
* The webform submission storage.
|
||||
* @param \Drupal\webform\WebformRequestInterface $request_handler
|
||||
* The webform request handler.
|
||||
*/
|
||||
public function __construct(WebformSubmissionStorageInterface $webform_submission_storage, WebformRequestInterface $request_handler) {
|
||||
$this->submissionStorage = $webform_submission_storage;
|
||||
$this->requestHandler = $request_handler;
|
||||
list($this->webform, $this->sourceEntity) = $this->requestHandler->getWebformEntities();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function create(ContainerInterface $container) {
|
||||
return new static(
|
||||
$container->get('entity.manager')->getStorage('webform_submission'),
|
||||
$container->get('webform.request')
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function buildForm(array $form, FormStateInterface $form_state) {
|
||||
$available_columns = $this->submissionStorage->getColumns($this->webform, $this->sourceEntity, NULL, TRUE);
|
||||
$custom_columns = $this->submissionStorage->getCustomColumns($this->webform, $this->sourceEntity, NULL, TRUE);
|
||||
// Change sid's # to an actual label.
|
||||
$available_columns['sid']['title'] = $this->t('Submission ID');
|
||||
if (isset($custom_columns['sid'])) {
|
||||
$custom_columns['sid']['title'] = $this->t('Submission ID');
|
||||
}
|
||||
|
||||
// Columns.
|
||||
$columns_options = [];
|
||||
foreach ($available_columns as $column_name => $column) {
|
||||
$title = (strpos($column_name, 'element__') === 0) ? ['data' => ['#markup' => '<b>' . $column['title'] . '</b>']] : $column['title'];
|
||||
$key = (isset($column['key'])) ? str_replace('webform_', '', $column['key']) : $column['name'];
|
||||
$columns_options[$column_name] = ['title' => $title, 'key' => $key];
|
||||
}
|
||||
$columns_keys = array_keys($custom_columns);
|
||||
$columns_default_value = array_combine($columns_keys, $columns_keys);
|
||||
$form['columns'] = [
|
||||
'#type' => 'webform_tableselect_sort',
|
||||
'#header' => [
|
||||
'title' => $this->t('Title'),
|
||||
'key' => $this->t('Key'),
|
||||
],
|
||||
'#options' => $columns_options,
|
||||
'#default_value' => $columns_default_value,
|
||||
];
|
||||
|
||||
// Get available sort options.
|
||||
$sort_options = [];
|
||||
$sort_columns = $available_columns;
|
||||
ksort($sort_columns);
|
||||
foreach ($sort_columns as $column_name => $column) {
|
||||
if (!isset($column['sort']) || $column['sort'] === TRUE) {
|
||||
$sort_options[$column_name] = (string) $column['title'];
|
||||
};
|
||||
}
|
||||
asort($sort_options);
|
||||
|
||||
// Sort and direction.
|
||||
// Display available columns sorted alphabetically.
|
||||
$sort = $this->webform->getState($this->getStateKey('sort'), 'serial');
|
||||
$direction = $this->webform->getState($this->getStateKey('direction'), 'desc');
|
||||
$form['sort'] = [
|
||||
'#prefix' => '<div class="container-inline">',
|
||||
'#type' => 'select',
|
||||
'#field_prefix' => $this->t('Sort by'),
|
||||
'#options' => $sort_options,
|
||||
'#default_value' => $sort,
|
||||
];
|
||||
$form['direction'] = [
|
||||
'#type' => 'select',
|
||||
'#field_prefix' => ' ' . $this->t('in', [], ['context' => 'Sort by {sort} in {direction} order.']) . ' ',
|
||||
'#field_suffix' => ' ' . $this->t('order', [], ['context' => 'Sort by {sort} in {direction} order.']) . '.',
|
||||
'#options' => [
|
||||
'asc' => $this->t('Ascending (ASC)'),
|
||||
'desc' => $this->t('Descending (DESC)'),
|
||||
],
|
||||
'#default_value' => $direction,
|
||||
'#suffix' => '</div>',
|
||||
];
|
||||
|
||||
// Limit.
|
||||
$limit = $this->webform->getState($this->getStateKey('limit'), NULL);
|
||||
$form['limit'] = [
|
||||
'#type' => 'select',
|
||||
'#field_prefix' => $this->t('Show', [], ['context' => 'Show {limit} results per page.']),
|
||||
'#field_suffix' => $this->t('results per page') . '.',
|
||||
'#options' => [
|
||||
'20' => '20',
|
||||
'50' => '50',
|
||||
'100' => '100',
|
||||
'200' => '200',
|
||||
'500' => '500',
|
||||
'1000' => '1000',
|
||||
'0' => $this->t('All'),
|
||||
],
|
||||
'#default_value' => ($limit != NULL) ? $limit : 50,
|
||||
];
|
||||
|
||||
// Default configuration.
|
||||
if (empty($this->sourceEntity)) {
|
||||
$form['config'] = [
|
||||
'#type' => 'details',
|
||||
'#title' => $this->t('Configuration settings'),
|
||||
];
|
||||
$form['config']['default'] = [
|
||||
'#type' => 'checkbox',
|
||||
'#title' => $this->t('Use as default configuration'),
|
||||
'#description' => $this->t('If checked, the above settings will be used as the default configuration for all associated Webform nodes.'),
|
||||
'#return_value' => TRUE,
|
||||
'#default_value' => $this->webform->getState($this->getStateKey('default'), TRUE),
|
||||
];
|
||||
}
|
||||
|
||||
// Format settings.
|
||||
$format = $this->webform->getState($this->getStateKey('format'), [
|
||||
'header_format' => 'label',
|
||||
'element_format' => 'value',
|
||||
]);
|
||||
$form['format'] = [
|
||||
'#type' => 'details',
|
||||
'#title' => $this->t('Format settings'),
|
||||
'#tree' => TRUE,
|
||||
];
|
||||
$form['format']['header_format'] = [
|
||||
'#type' => 'radios',
|
||||
'#title' => $this->t('Column header format'),
|
||||
'#description' => $this->t('Choose whether to show the element label or element key in each column header.'),
|
||||
'#options' => [
|
||||
'label' => $this->t('Element titles (label)'),
|
||||
'key' => $this->t('Element keys (key)'),
|
||||
],
|
||||
'#default_value' => $format['header_format'],
|
||||
];
|
||||
$form['format']['element_format'] = [
|
||||
'#type' => 'radios',
|
||||
'#title' => $this->t('Element format'),
|
||||
'#options' => [
|
||||
'value' => $this->t('Labels/values, the human-readable value (value)'),
|
||||
'raw' => $this->t('Raw values, the raw value stored in the database (raw)'),
|
||||
],
|
||||
'#default_value' => $format['element_format'],
|
||||
];
|
||||
|
||||
// Build actions.
|
||||
$form['actions']['#type'] = 'actions';
|
||||
$form['actions']['save'] = [
|
||||
'#type' => 'submit',
|
||||
'#value' => $this->t('Save'),
|
||||
];
|
||||
$form['actions']['delete'] = [
|
||||
'#type' => 'submit',
|
||||
'#value' => $this->t('Reset'),
|
||||
'#attributes' => [
|
||||
'class' => ['button', 'button--danger'],
|
||||
],
|
||||
'#access' => $this->webform->hasState($this->getStateKey('columns')),
|
||||
'#submit' => ['::delete'],
|
||||
];
|
||||
return $form;
|
||||
}
|
||||
|
||||
/**
|
||||
* Build table row for a results columns.
|
||||
*
|
||||
* @param string $column_name
|
||||
* The column name.
|
||||
* @param array $column
|
||||
* The column.
|
||||
* @param bool $default_value
|
||||
* Whether the column should be checked.
|
||||
* @param int $weight
|
||||
* The columns weights.
|
||||
* @param int $delta
|
||||
* The max delta for the weight element.
|
||||
*
|
||||
* @return array
|
||||
* A renderable containing a table row for a results column.
|
||||
*/
|
||||
protected function buildRow($column_name, array $column, $default_value, $weight, $delta) {
|
||||
return [
|
||||
'#attributes' => ['class' => ['draggable']],
|
||||
'name' => [
|
||||
'#type' => 'checkbox',
|
||||
'#default_value' => $default_value,
|
||||
],
|
||||
'title' => [
|
||||
'#markup' => $column['title'],
|
||||
],
|
||||
'key' => [
|
||||
'#markup' => (isset($column['key'])) ? $column['key'] : $column['name'],
|
||||
],
|
||||
'weight' => [
|
||||
'#type' => 'weight',
|
||||
'#title' => $this->t('Weight for @label', ['@label' => $column['title']]),
|
||||
'#title_display' => 'invisible',
|
||||
'#attributes' => [
|
||||
'class' => ['table-sort-weight'],
|
||||
],
|
||||
'#delta' => $delta,
|
||||
'#default_value' => $weight,
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function validateForm(array &$form, FormStateInterface $form_state) {
|
||||
$columns = $form_state->getValue('columns');
|
||||
if (empty($columns)) {
|
||||
$form_state->setErrorByName('columns', $this->t('At least once column is required'));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function submitForm(array &$form, FormStateInterface $form_state) {
|
||||
// Set columns.
|
||||
$this->webform->setState($this->getStateKey('columns'), $form_state->getValue('columns'));
|
||||
|
||||
// Set sort, direction, limit.
|
||||
$this->webform->setState($this->getStateKey('sort'), $form_state->getValue('sort'));
|
||||
$this->webform->setState($this->getStateKey('direction'), $form_state->getValue('direction'));
|
||||
$this->webform->setState($this->getStateKey('limit'), (int) $form_state->getValue('limit'));
|
||||
$this->webform->setState($this->getStateKey('format'), $form_state->getValue('format'));
|
||||
|
||||
// Set default.
|
||||
if (empty($this->sourceEntity)) {
|
||||
$this->webform->setState($this->getStateKey('default'), $form_state->getValue('default'));
|
||||
}
|
||||
|
||||
// Display message.
|
||||
drupal_set_message($this->t('The customized table has been saved.'));
|
||||
|
||||
// Set redirect.
|
||||
$route_name = $this->requestHandler->getRouteName($this->webform, $this->sourceEntity, 'webform.results_table');
|
||||
$route_parameters = $this->requestHandler->getRouteParameters($this->webform, $this->sourceEntity);
|
||||
$form_state->setRedirect($route_name, $route_parameters);
|
||||
}
|
||||
|
||||
/**
|
||||
* Webform delete customized columns handler.
|
||||
*
|
||||
* @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 delete(array &$form, FormStateInterface $form_state) {
|
||||
$this->webform->deleteState($this->getStateKey('columns'));
|
||||
$this->webform->deleteState($this->getStateKey('sort'));
|
||||
$this->webform->deleteState($this->getStateKey('direction'));
|
||||
$this->webform->deleteState($this->getStateKey('limit'));
|
||||
$this->webform->deleteState($this->getStateKey('default'));
|
||||
$this->webform->deleteState($this->getStateKey('format'));
|
||||
drupal_set_message($this->t('The customized table has been reset.'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the state key for the custom data.
|
||||
*
|
||||
* @return string
|
||||
* The state key for the custom data.
|
||||
*/
|
||||
protected function getStateKey($name) {
|
||||
if ($source_entity = $this->sourceEntity) {
|
||||
return "results.custom.$name." . $source_entity->getEntityTypeId() . '.' . $source_entity->id();
|
||||
}
|
||||
else {
|
||||
return "results.custom.$name";
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,138 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\webform\Form;
|
||||
|
||||
use Drupal\Component\Utility\NestedArray;
|
||||
use Drupal\Core\Form\FormBase;
|
||||
use Drupal\Core\Form\FormStateInterface;
|
||||
use Drupal\webform\WebformSubmissionExporterInterface;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
|
||||
/**
|
||||
* Webform for webform results export webform.
|
||||
*/
|
||||
class WebformResultsExportForm extends FormBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getFormId() {
|
||||
return 'webform_results_export';
|
||||
}
|
||||
|
||||
/**
|
||||
* The webform submission exporter.
|
||||
*
|
||||
* @var \Drupal\webform\WebformSubmissionExporterInterface
|
||||
*/
|
||||
protected $submissionExporter;
|
||||
|
||||
/**
|
||||
* Constructs a WebformResultsExportForm object.
|
||||
*
|
||||
* @param \Drupal\webform\WebformSubmissionExporterInterface $webform_submission_exporter
|
||||
* The webform submission exported.
|
||||
*/
|
||||
public function __construct(WebformSubmissionExporterInterface $webform_submission_exporter) {
|
||||
$this->submissionExporter = $webform_submission_exporter;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function create(ContainerInterface $container) {
|
||||
return new static(
|
||||
$container->get('webform_submission.exporter')
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function buildForm(array $form, FormStateInterface $form_state) {
|
||||
// Set the merged default (global setting), saved, and user export options
|
||||
// into the webform's state.
|
||||
$settings_options = $this->config('webform.settings')->get('export');
|
||||
$saved_options = $this->submissionExporter->getWebformOptions();
|
||||
$user_options = $this->submissionExporter->getValuesFromInput($form_state->getUserInput());
|
||||
$export_options = NestedArray::mergeDeep($settings_options, $saved_options, $user_options);
|
||||
|
||||
// Build the webform.
|
||||
$this->submissionExporter->buildExportOptionsForm($form, $form_state, $export_options);
|
||||
|
||||
// Build actions.
|
||||
$form['actions']['#type'] = 'actions';
|
||||
$form['actions']['submit'] = [
|
||||
'#type' => 'submit',
|
||||
'#value' => $this->t('Download'),
|
||||
'#button_type' => 'primary',
|
||||
];
|
||||
$form['actions']['save'] = [
|
||||
'#type' => 'submit',
|
||||
'#value' => $this->t('Save settings'),
|
||||
'#submit' => ['::save'],
|
||||
];
|
||||
$form['actions']['delete'] = [
|
||||
'#type' => 'submit',
|
||||
'#value' => $this->t('Reset settings'),
|
||||
'#attributes' => [
|
||||
'class' => ['button', 'button--danger'],
|
||||
],
|
||||
'#access' => ($saved_options) ? TRUE : FALSE,
|
||||
'#submit' => ['::delete'],
|
||||
];
|
||||
return $form;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function submitForm(array &$form, FormStateInterface $form_state) {
|
||||
$export_options = $this->submissionExporter->getValuesFromInput($form_state->getValues());
|
||||
|
||||
// Implode exclude columns.
|
||||
$export_options['excluded_columns'] = implode(',', $export_options['excluded_columns']);
|
||||
|
||||
if ($source_entity = $this->submissionExporter->getSourceEntity()) {
|
||||
$entity_type = $source_entity->getEntityTypeId();
|
||||
$entity_id = $source_entity->id();
|
||||
$route_parameters = [$entity_type => $entity_id];
|
||||
$route_options = ['query' => $export_options];
|
||||
$form_state->setRedirect('entity.' . $entity_type . '.webform.results_export', $route_parameters, $route_options);
|
||||
}
|
||||
elseif ($webform = $this->submissionExporter->getWebform()) {
|
||||
$route_parameters = ['webform' => $webform->id()];
|
||||
$route_options = ['query' => $export_options];
|
||||
$form_state->setRedirect('entity.webform.results_export', $route_parameters, $route_options);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Webform save configuration handler.
|
||||
*
|
||||
* @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 save(array &$form, FormStateInterface $form_state) {
|
||||
// Save the export options to the webform's state.
|
||||
$export_options = $this->submissionExporter->getValuesFromInput($form_state->getValues());
|
||||
$this->submissionExporter->setWebformOptions($export_options);
|
||||
drupal_set_message($this->t('The download settings have been saved.'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Webform delete configuration handler.
|
||||
*
|
||||
* @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 delete(array &$form, FormStateInterface $form_state) {
|
||||
$this->submissionExporter->deleteWebformOptions();
|
||||
drupal_set_message($this->t('The download settings have been reset.'));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,116 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\webform\Form;
|
||||
|
||||
use Drupal\Core\Entity\ContentEntityDeleteForm;
|
||||
use Drupal\Core\Entity\EntityManagerInterface;
|
||||
use Drupal\Core\Form\FormStateInterface;
|
||||
use Drupal\Core\Url;
|
||||
use Drupal\webform\WebformRequestInterface;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
|
||||
/**
|
||||
* Provides a confirmation webform for deleting a webform submission.
|
||||
*/
|
||||
class WebformSubmissionDeleteForm extends ContentEntityDeleteForm {
|
||||
|
||||
/**
|
||||
* The webform entity.
|
||||
*
|
||||
* @var \Drupal\webform\WebformInterface
|
||||
*/
|
||||
protected $webform;
|
||||
|
||||
|
||||
/**
|
||||
* The webform submission entity.
|
||||
*
|
||||
* @var \Drupal\webform\WebformSubmissionInterface
|
||||
*/
|
||||
protected $webformSubmission;
|
||||
|
||||
/**
|
||||
* The webform source entity.
|
||||
*
|
||||
* @var \Drupal\Core\Entity\EntityInterface
|
||||
*/
|
||||
protected $sourceEntity;
|
||||
|
||||
/**
|
||||
* Webform request handler.
|
||||
*
|
||||
* @var \Drupal\webform\WebformRequestInterface
|
||||
*/
|
||||
protected $requestHandler;
|
||||
|
||||
/**
|
||||
* Constructs a WebformSubmissionDeleteForm object.
|
||||
*
|
||||
* @param \Drupal\Core\Entity\EntityManagerInterface $entity_manager
|
||||
* The entity manager.
|
||||
* @param \Drupal\webform\WebformRequestInterface $request_handler
|
||||
* The webform request handler.
|
||||
*/
|
||||
public function __construct(EntityManagerInterface $entity_manager, WebformRequestInterface $request_handler) {
|
||||
parent::__construct($entity_manager);
|
||||
$this->requestHandler = $request_handler;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function create(ContainerInterface $container) {
|
||||
return new static(
|
||||
$container->get('entity.manager'),
|
||||
$container->get('webform.request')
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function buildForm(array $form, FormStateInterface $form_state) {
|
||||
list($this->webformSubmission, $this->sourceEntity) = $this->requestHandler->getWebformSubmissionEntities();
|
||||
$this->webform = $this->webformSubmission->getWebform();
|
||||
return parent::buildForm($form, $form_state);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getQuestion() {
|
||||
return $this->t('Are you sure you want to delete @title?', ['@title' => $this->webformSubmission->label()]);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getDeletionMessage() {
|
||||
return $this->t('@title has been deleted.', ['@title' => $this->webformSubmission->label()]);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getCancelUrl() {
|
||||
$route_name = $this->requestHandler->getRouteName($this->webform, $this->sourceEntity, 'webform.results_submissions');
|
||||
$route_parameters = $this->requestHandler->getRouteParameters($this->webform, $this->sourceEntity);
|
||||
return new Url($route_name, $route_parameters);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getRedirectUrl() {
|
||||
return $this->getCancelUrl();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function logDeletionMessage() {
|
||||
// Deletion logging is handled via WebformSubmissionStorage.
|
||||
// @see \Drupal\webform\WebformSubmissionStorage::delete
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,125 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\webform\Form;
|
||||
|
||||
use Drupal\Core\Entity\EntityManagerInterface;
|
||||
use Drupal\Core\Form\ConfirmFormBase;
|
||||
use Drupal\Core\Form\FormStateInterface;
|
||||
use Drupal\Core\Url;
|
||||
use Drupal\user\PrivateTempStoreFactory;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
use Symfony\Component\HttpFoundation\RedirectResponse;
|
||||
|
||||
/**
|
||||
* Provides a webform submission deletion confirmation form.
|
||||
*/
|
||||
class WebformSubmissionDeleteMultiple extends ConfirmFormBase {
|
||||
|
||||
/**
|
||||
* The array of webform_submissions to delete.
|
||||
*
|
||||
* @var string[][]
|
||||
*/
|
||||
protected $webformSubmissionInfo = [];
|
||||
|
||||
/**
|
||||
* The tempstore factory.
|
||||
*
|
||||
* @var \Drupal\user\PrivateTempStoreFactory
|
||||
*/
|
||||
protected $tempStoreFactory;
|
||||
|
||||
/**
|
||||
* The webform submission storage.
|
||||
*
|
||||
* @var \Drupal\Core\Entity\EntityStorageInterface
|
||||
*/
|
||||
protected $manager;
|
||||
|
||||
/**
|
||||
* Constructs a DeleteMultiple form object.
|
||||
*
|
||||
* @param \Drupal\user\PrivateTempStoreFactory $temp_store_factory
|
||||
* The tempstore factory.
|
||||
* @param \Drupal\Core\Entity\EntityManagerInterface $manager
|
||||
* The entity manager.
|
||||
*/
|
||||
public function __construct(PrivateTempStoreFactory $temp_store_factory, EntityManagerInterface $manager) {
|
||||
$this->tempStoreFactory = $temp_store_factory;
|
||||
$this->storage = $manager->getStorage('webform_submission');
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function create(ContainerInterface $container) {
|
||||
return new static(
|
||||
$container->get('user.private_tempstore'),
|
||||
$container->get('entity.manager')
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getFormId() {
|
||||
return 'webform_submission_multiple_delete_confirm';
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getQuestion() {
|
||||
return $this->formatPlural(count($this->webformSubmissionInfo), 'Are you sure you want to delete this submission?', 'Are you sure you want to delete these submissions?');
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getCancelUrl() {
|
||||
return new Url('entity.webform_submission.collection');
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getConfirmText() {
|
||||
return t('Delete');
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function buildForm(array $form, FormStateInterface $form_state) {
|
||||
/** @var \Drupal\webform\WebformSubmissionInterface[] $webform_submissions */
|
||||
$webform_submissions = $this->tempStoreFactory->get('webform_submission_multiple_delete_confirm')->get(\Drupal::currentUser()->id());
|
||||
if (empty($webform_submissions)) {
|
||||
return new RedirectResponse($this->getCancelUrl()->setAbsolute()->toString());
|
||||
}
|
||||
|
||||
$form['webform_submissions'] = [
|
||||
'#theme' => 'item_list',
|
||||
'#items' => array_map(function ($webform_submission) {
|
||||
return $webform_submission->label();
|
||||
}, $webform_submissions),
|
||||
];
|
||||
$form = parent::buildForm($form, $form_state);
|
||||
return $form;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function submitForm(array &$form, FormStateInterface $form_state) {
|
||||
/** @var \Drupal\webform\WebformSubmissionInterface[] $webform_submissions */
|
||||
$webform_submissions = $this->tempStoreFactory->get('webform_submission_multiple_delete_confirm')->get(\Drupal::currentUser()->id());
|
||||
if ($form_state->getValue('confirm') && !empty($webform_submissions)) {
|
||||
$this->storage->delete($webform_submissions);
|
||||
$this->logger('content')->notice('Deleted @count submission.', ['@count' => count($webform_submissions)]);
|
||||
$this->tempStoreFactory->get('webform_submission_multiple_delete_confirm')->delete(\Drupal::currentUser()->id());
|
||||
}
|
||||
|
||||
$form_state->setRedirect('entity.webform_submission.collection');
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,30 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\webform\Form;
|
||||
|
||||
use Drupal\Core\Form\FormStateInterface;
|
||||
|
||||
/**
|
||||
* Provides the webform submission filter webform.
|
||||
*/
|
||||
class WebformSubmissionFilterForm extends WebformFilterFormBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getFormId() {
|
||||
return 'webform_submission_filter_form';
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function buildForm(array $form, FormStateInterface $form_state, $search = NULL, $state = NULL, array $state_options = []) {
|
||||
$form = parent::buildForm($form, $form_state, $search, $state, $state_options);
|
||||
$form['filter']['#title'] = $this->t('Filter submissions');
|
||||
$form['filter']['search']['#title'] = $this->t('Filter by submitted data and/or notes');
|
||||
$form['filter']['search']['#placeholder'] = $this->t('Filter by submitted data and/or notes');
|
||||
return $form;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,231 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\webform\Form;
|
||||
|
||||
use Drupal\Core\Form\FormBase;
|
||||
use Drupal\Core\Form\FormStateInterface;
|
||||
use Drupal\webform\Plugin\WebformHandler\EmailWebformHandler;
|
||||
use Drupal\webform\WebformRequestInterface;
|
||||
use Drupal\webform\WebformSubmissionInterface;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
|
||||
/**
|
||||
* Defines a webform that resends webform submission.
|
||||
*/
|
||||
class WebformSubmissionResendForm extends FormBase {
|
||||
|
||||
/**
|
||||
* A webform submission.
|
||||
*
|
||||
* @var \Drupal\webform\WebformSubmissionInterface
|
||||
*/
|
||||
protected $webformSubmission;
|
||||
|
||||
/**
|
||||
* The source entity.
|
||||
*
|
||||
* @var \Drupal\Core\Entity\EntityInterface
|
||||
*/
|
||||
protected $entity;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getFormId() {
|
||||
return 'webform_submission_resend';
|
||||
}
|
||||
|
||||
/**
|
||||
* Webform request handler.
|
||||
*
|
||||
* @var \Drupal\webform\WebformRequestInterface
|
||||
*/
|
||||
protected $requestHandler;
|
||||
|
||||
/**
|
||||
* Constructs a WebformResultsResendForm object.
|
||||
*
|
||||
* @param \Drupal\webform\WebformRequestInterface $request_handler
|
||||
* The webform request handler.
|
||||
*/
|
||||
public function __construct(WebformRequestInterface $request_handler) {
|
||||
$this->requestHandler = $request_handler;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function create(ContainerInterface $container) {
|
||||
return new static(
|
||||
$container->get('webform.request')
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function buildForm(array $form, FormStateInterface $form_state, WebformSubmissionInterface $webform_submission = NULL) {
|
||||
$this->webformSubmission = $webform_submission;
|
||||
|
||||
$handlers = $webform_submission->getWebform()->getHandlers();
|
||||
|
||||
/** @var \Drupal\webform\WebformHandlerMessageInterface[] $message_handlers */
|
||||
$message_handlers = [];
|
||||
foreach ($handlers as $handler_id => $handler) {
|
||||
if ($handler instanceof EmailWebformHandler) {
|
||||
$message_handlers[$handler_id] = $handler;
|
||||
}
|
||||
}
|
||||
|
||||
// Get header.
|
||||
$header = [];
|
||||
$header['title'] = [
|
||||
'data' => $this->t('Title / Description'),
|
||||
];
|
||||
$header['id'] = [
|
||||
'data' => $this->t('ID'),
|
||||
'class' => [RESPONSIVE_PRIORITY_LOW],
|
||||
];
|
||||
$header['summary'] = [
|
||||
'data' => $this->t('summary'),
|
||||
'class' => [RESPONSIVE_PRIORITY_LOW],
|
||||
];
|
||||
$header['status'] = [
|
||||
'data' => $this->t('Status'),
|
||||
'class' => [RESPONSIVE_PRIORITY_LOW],
|
||||
];
|
||||
|
||||
// Get options.
|
||||
$options = [];
|
||||
foreach ($message_handlers as $index => $message_handler) {
|
||||
$message = $message_handler->getMessage($this->webformSubmission);
|
||||
|
||||
$options[$index]['title'] = [
|
||||
'data' => [
|
||||
'label' => [
|
||||
'#type' => 'label',
|
||||
'#title' => $message_handler->label() . ': ' . $message_handler->description(),
|
||||
'#title_display' => NULL,
|
||||
'#for' => 'edit-message-handler-id-' . str_replace('_', '-', $message_handler->getHandlerId()),
|
||||
],
|
||||
],
|
||||
];
|
||||
$options[$index]['id'] = [
|
||||
'data' => $message_handler->getHandlerId(),
|
||||
];
|
||||
$options[$index]['summary'] = [
|
||||
'data' => $message_handler->getMessageSummary($message),
|
||||
];
|
||||
$options[$index]['status'] = ($message_handler->isEnabled()) ? $this->t('Enabled') : $this->t('Disabled');
|
||||
}
|
||||
|
||||
// Get message handler id.
|
||||
if (empty($form_state->getValue('message_handler_id'))) {
|
||||
reset($options);
|
||||
$message_handler_id = key($options);
|
||||
$form_state->setValue('message_handler_id', $message_handler_id);
|
||||
}
|
||||
else {
|
||||
$message_handler_id = $form_state->getValue('message_handler_id');
|
||||
}
|
||||
|
||||
$message_handler = $this->getMessageHandler($form_state);
|
||||
$form['message_handler_id'] = [
|
||||
'#type' => 'tableselect',
|
||||
'#header' => $header,
|
||||
'#options' => $options,
|
||||
'#js_select' => TRUE,
|
||||
'#empty' => $this->t('No messages are available.'),
|
||||
'#multiple' => FALSE,
|
||||
'#default_value' => $message_handler_id,
|
||||
'#ajax' => [
|
||||
'callback' => '::updateMessage',
|
||||
'wrapper' => 'edit-webform-message-wrapper',
|
||||
],
|
||||
];
|
||||
|
||||
// Message.
|
||||
$form['message'] = [
|
||||
'#type' => 'details',
|
||||
'#title' => $this->t('Message'),
|
||||
'#open' => TRUE,
|
||||
'#tree' => TRUE,
|
||||
'#prefix' => '<div id="edit-webform-message-wrapper">',
|
||||
'#suffix' => '</div>',
|
||||
];
|
||||
$message = $message_handler->getMessage($webform_submission);
|
||||
$form['message'] += $message_handler->resendMessageForm($message);
|
||||
|
||||
// Add resend button.
|
||||
$form['submit'] = [
|
||||
'#type' => 'submit',
|
||||
'#value' => $this->t('Resend message'),
|
||||
];
|
||||
|
||||
// Add submission navigation.
|
||||
$source_entity = $this->requestHandler->getCurrentSourceEntity('webform_submission');
|
||||
$form['navigation'] = [
|
||||
'#theme' => 'webform_submission_navigation',
|
||||
'#webform_submission' => $webform_submission,
|
||||
'#weight' => -20,
|
||||
];
|
||||
$form['information'] = [
|
||||
'#theme' => 'webform_submission_information',
|
||||
'#webform_submission' => $webform_submission,
|
||||
'#source_entity' => $source_entity,
|
||||
'#weight' => -19,
|
||||
];
|
||||
$form['#attached']['library'][] = 'webform/webform.admin';
|
||||
|
||||
return $form;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles switching between messages.
|
||||
*
|
||||
* @param array $form
|
||||
* An associative array containing the structure of the form.
|
||||
* @param \Drupal\Core\Form\FormStateInterface $form_state
|
||||
* The current state of the form.
|
||||
*
|
||||
* @return array
|
||||
* An associative array containing an email message.
|
||||
*/
|
||||
public function updateMessage(array $form, FormStateInterface $form_state) {
|
||||
$message_handler = $this->getMessageHandler($form_state);
|
||||
$message = $message_handler->getMessage($this->webformSubmission);
|
||||
foreach ($message as $key => $value) {
|
||||
$form['message'][$key]['#value'] = $value;
|
||||
}
|
||||
return $form['message'];
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function submitForm(array &$form, FormStateInterface $form_state) {
|
||||
$params = $form_state->getValue('message');
|
||||
$message_handler = $this->getMessageHandler($form_state);
|
||||
$message_handler->sendMessage($params);
|
||||
|
||||
$t_args = [
|
||||
'%label' => $message_handler->label(),
|
||||
];
|
||||
drupal_set_message($this->t('Successfully re-sent %label.', $t_args));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get message handler from webform state.
|
||||
*
|
||||
* @param \Drupal\Core\Form\FormStateInterface $form_state
|
||||
* The current state of the form.
|
||||
*
|
||||
* @return \Drupal\webform\WebformHandlerMessageInterface
|
||||
* The current message handler.
|
||||
*/
|
||||
protected function getMessageHandler(FormStateInterface $form_state) {
|
||||
$message_handler_id = $form_state->getValue('message_handler_id');
|
||||
return $this->webformSubmission->getWebform()->getHandler($message_handler_id);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,210 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\webform\Form;
|
||||
|
||||
use Drupal\Core\Entity\EntityInterface;
|
||||
use Drupal\Core\Form\ConfirmFormBase;
|
||||
use Drupal\Core\Form\FormStateInterface;
|
||||
use Drupal\webform\WebformInterface;
|
||||
use Drupal\webform\WebformRequestInterface;
|
||||
use Drupal\webform\WebformSubmissionStorageInterface;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
|
||||
/**
|
||||
* Base webform for deleting webform submission.
|
||||
*/
|
||||
abstract class WebformSubmissionsDeleteFormBase extends ConfirmFormBase {
|
||||
|
||||
/**
|
||||
* Default number of submission to be deleted during batch processing.
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
protected $batchLimit = 1000;
|
||||
|
||||
/**
|
||||
* The webform entity.
|
||||
*
|
||||
* @var \Drupal\webform\WebformInterface
|
||||
*/
|
||||
protected $webform;
|
||||
|
||||
/**
|
||||
* The webform source entity.
|
||||
*
|
||||
* @var \Drupal\Core\Entity\EntityInterface
|
||||
*/
|
||||
protected $sourceEntity;
|
||||
|
||||
/**
|
||||
* The webform submission storage.
|
||||
*
|
||||
* @var \Drupal\webform\WebformSubmissionStorageInterface
|
||||
*/
|
||||
protected $submissionStorage;
|
||||
|
||||
/**
|
||||
* Webform request handler.
|
||||
*
|
||||
* @var \Drupal\webform\WebformRequestInterface
|
||||
*/
|
||||
protected $requestHandler;
|
||||
|
||||
/**
|
||||
* Constructs a WebformResultsDeleteFormBase object.
|
||||
*
|
||||
* @param \Drupal\webform\WebformSubmissionStorageInterface $webform_submission_storage
|
||||
* The webform submission storage.
|
||||
* @param \Drupal\webform\WebformRequestInterface $request_handler
|
||||
* The webform request handler.
|
||||
*/
|
||||
public function __construct(WebformSubmissionStorageInterface $webform_submission_storage, WebformRequestInterface $request_handler) {
|
||||
$this->submissionStorage = $webform_submission_storage;
|
||||
$this->requestHandler = $request_handler;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function create(ContainerInterface $container) {
|
||||
return new static(
|
||||
$container->get('entity.manager')->getStorage('webform_submission'),
|
||||
$container->get('webform.request')
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getConfirmText() {
|
||||
return $this->t('Clear');
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function buildForm(array $form, FormStateInterface $form_state) {
|
||||
list($this->webform, $this->sourceEntity) = $this->requestHandler->getWebformEntities();
|
||||
return parent::buildForm($form, $form_state);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function submitForm(array &$form, FormStateInterface $form_state) {
|
||||
$form_state->setRedirectUrl($this->getCancelUrl());
|
||||
if ($this->submissionStorage->getTotal($this->webform, $this->sourceEntity) < $this->getBatchLimit()) {
|
||||
$this->submissionStorage->deleteAll($this->webform, $this->sourceEntity);
|
||||
drupal_set_message($this->getFinishedMessage());
|
||||
}
|
||||
else {
|
||||
$this->batchSet($this->webform, $this->sourceEntity);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Message to displayed after submissions are deleted.
|
||||
*
|
||||
* @return \Drupal\Core\StringTranslation\TranslatableMarkup
|
||||
* Message to be displayed after delete has finished.
|
||||
*/
|
||||
public function getFinishedMessage() {
|
||||
return $this->t('Webform submissions cleared.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Batch API; Initialize batch operations.
|
||||
*
|
||||
* @param \Drupal\webform\WebformInterface|null $webform
|
||||
* The webform.
|
||||
* @param \Drupal\Core\Entity\EntityInterface|null $entity
|
||||
* The webform's source entity.
|
||||
*/
|
||||
public function batchSet(WebformInterface $webform = NULL, EntityInterface $entity = NULL) {
|
||||
$parameters = [
|
||||
$webform,
|
||||
$entity,
|
||||
$this->submissionStorage->getMaxSubmissionId($webform, $entity),
|
||||
];
|
||||
$batch = [
|
||||
'title' => $this->t('Clear submissions'),
|
||||
'init_message' => $this->t('Clearing submission data'),
|
||||
'error_message' => $this->t('The submissions could not be cleared because an error occurred.'),
|
||||
'operations' => [
|
||||
[[$this, 'batchProcess'], $parameters],
|
||||
],
|
||||
'finished' => [$this, 'batchFinish'],
|
||||
];
|
||||
|
||||
batch_set($batch);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the number of submissions to be deleted with each batch.
|
||||
*
|
||||
* @return int
|
||||
* Number of submissions to be deleted with each batch.
|
||||
*/
|
||||
public function getBatchLimit() {
|
||||
return $this->config('webform.settings')->get('batch.default_batch_delete_size') ?: $this->batchLimit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Batch API callback; Delete submissions.
|
||||
*
|
||||
* @param \Drupal\webform\WebformInterface|null $webform
|
||||
* The webform.
|
||||
* @param \Drupal\Core\Entity\EntityInterface|null $entity
|
||||
* The webform's source entity.
|
||||
* @param int $max_sid
|
||||
* The max submission ID to be delete.
|
||||
* @param mixed|array $context
|
||||
* The batch current context.
|
||||
*/
|
||||
public function batchProcess(WebformInterface $webform = NULL, EntityInterface $entity = NULL, $max_sid, &$context) {
|
||||
// ISSUE:
|
||||
// $this->submissionStorage is not being setup via
|
||||
// WebformSubmissionsDeleteFormBase::__construct.
|
||||
//
|
||||
// WORKAROUND:
|
||||
// Reset it for each batch process.
|
||||
$this->submissionStorage = \Drupal::entityTypeManager()->getStorage('webform_submission');
|
||||
|
||||
if (empty($context['sandbox'])) {
|
||||
$context['sandbox']['progress'] = 0;
|
||||
$context['sandbox']['max'] = $this->submissionStorage->getTotal($webform, $entity);
|
||||
$context['results']['webform'] = $webform;
|
||||
$context['results']['entity'] = $entity;
|
||||
}
|
||||
|
||||
// Track progress.
|
||||
$context['sandbox']['progress'] += $this->submissionStorage->deleteAll($webform, $entity, $this->getBatchLimit(), $max_sid);
|
||||
|
||||
$context['message'] = $this->t('Deleting @count of @total submissions...', ['@count' => $context['sandbox']['progress'], '@total' => $context['sandbox']['max']]);
|
||||
|
||||
// Track finished.
|
||||
if ($context['sandbox']['progress'] != $context['sandbox']['max']) {
|
||||
$context['finished'] = $context['sandbox']['progress'] / $context['sandbox']['max'];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Batch API callback; Completed deletion.
|
||||
*
|
||||
* @param bool $success
|
||||
* TRUE if batch successfully completed.
|
||||
* @param array $results
|
||||
* Batch results.
|
||||
* @param array $operations
|
||||
* An array of function calls (not used in this function).
|
||||
*/
|
||||
public function batchFinish($success = FALSE, array $results, array $operations) {
|
||||
if (!$success) {
|
||||
drupal_set_message($this->t('Finished with an error.'));
|
||||
}
|
||||
else {
|
||||
drupal_set_message($this->getFinishedMessage());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,73 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\webform\Form;
|
||||
|
||||
use Drupal\Core\Form\FormStateInterface;
|
||||
use Drupal\Core\Url;
|
||||
|
||||
/**
|
||||
* Webform for webform submission purge webform.
|
||||
*/
|
||||
class WebformSubmissionsPurgeForm extends WebformSubmissionsDeleteFormBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getFormId() {
|
||||
return 'webform_submissions_purge';
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getQuestion() {
|
||||
return $this->t('Are you sure you want to delete all submissions?');
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getConfirmText() {
|
||||
return $this->t('Purge');
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getCancelUrl() {
|
||||
return new Url('entity.webform_submission.collection');
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getFinishedMessage() {
|
||||
return $this->t('Webform submissions purged.');
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function buildForm(array $form, FormStateInterface $form_state) {
|
||||
$form = parent::buildForm($form, $form_state);
|
||||
|
||||
$submission_total = \Drupal::entityQuery('webform_submission')->count()->execute();
|
||||
$form_total = \Drupal::entityQuery('webform')->count()->execute();
|
||||
$t_args = [
|
||||
'@submission_total' => $submission_total,
|
||||
'@submissions' => $this->formatPlural($submission_total, $this->t('submission'), $this->t('submissions')),
|
||||
'@form_total' => $form_total,
|
||||
'@forms' => $this->formatPlural($form_total, $this->t('webform'), $this->t('webforms')),
|
||||
];
|
||||
|
||||
$form['confirm'] = [
|
||||
'#type' => 'checkbox',
|
||||
'#title' => $this->t('Are you sure you want to delete @submission_total @submissions in @form_total @forms?', $t_args),
|
||||
'#required' => TRUE,
|
||||
'#weight' => -10,
|
||||
];
|
||||
|
||||
return $form;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,32 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\webform\Normalizer;
|
||||
|
||||
use Drupal\hal\Normalizer\EntityReferenceItemNormalizer;
|
||||
use Drupal\webform\Plugin\Field\FieldType\WebformEntityReferenceItem;
|
||||
|
||||
/**
|
||||
* Defines a class for normalizing WebformEntityReferenceItems.
|
||||
*/
|
||||
class WebformEntityReferenceItemNormalizer extends EntityReferenceItemNormalizer {
|
||||
|
||||
/**
|
||||
* The interface or class that this Normalizer supports.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $supportedInterfaceOrClass = WebformEntityReferenceItem::class;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function constructValue($data, $context) {
|
||||
$value = parent::constructValue($data, $context);
|
||||
if ($value) {
|
||||
$value['default_data'] = $data['default_data'];
|
||||
$value['status'] = $data['status'];
|
||||
}
|
||||
return $value;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,93 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\webform\Plugin\Action;
|
||||
|
||||
use Drupal\Core\Action\ActionBase;
|
||||
use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
|
||||
use Drupal\Core\Session\AccountInterface;
|
||||
use Drupal\user\PrivateTempStoreFactory;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
|
||||
/**
|
||||
* Redirects to a webform submission deletion form.
|
||||
*
|
||||
* @Action(
|
||||
* id = "webform_submission_delete_action",
|
||||
* label = @Translation("Delete submission"),
|
||||
* type = "webform_submission",
|
||||
* confirm_form_route_name = "webform_submission.multiple_delete_confirm"
|
||||
* )
|
||||
*/
|
||||
class DeleteWebformSubmission extends ActionBase implements ContainerFactoryPluginInterface {
|
||||
|
||||
/**
|
||||
* The tempstore factory.
|
||||
*
|
||||
* @var \Drupal\user\PrivateTempStoreFactory
|
||||
*/
|
||||
protected $tempStoreFactory;
|
||||
|
||||
/**
|
||||
* The current user.
|
||||
*
|
||||
* @var \Drupal\Core\Session\AccountInterface
|
||||
*/
|
||||
protected $currentUser;
|
||||
|
||||
/**
|
||||
* Constructs a DeleteWebformSubmission object.
|
||||
*
|
||||
* @param array $configuration
|
||||
* A configuration array containing information about the plugin instance.
|
||||
* @param string $plugin_id
|
||||
* The plugin ID for the plugin instance.
|
||||
* @param mixed $plugin_definition
|
||||
* The plugin implementation definition.
|
||||
* @param \Drupal\user\PrivateTempStoreFactory $temp_store_factory
|
||||
* The tempstore factory.
|
||||
* @param \Drupal\Core\Session\AccountInterface $current_user
|
||||
* Current user.
|
||||
*/
|
||||
public function __construct(array $configuration, $plugin_id, $plugin_definition, PrivateTempStoreFactory $temp_store_factory, AccountInterface $current_user) {
|
||||
$this->currentUser = $current_user;
|
||||
$this->tempStoreFactory = $temp_store_factory;
|
||||
|
||||
parent::__construct($configuration, $plugin_id, $plugin_definition);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
|
||||
return new static(
|
||||
$configuration,
|
||||
$plugin_id,
|
||||
$plugin_definition,
|
||||
$container->get('user.private_tempstore'),
|
||||
$container->get('current_user')
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function executeMultiple(array $entities) {
|
||||
$this->tempStoreFactory->get('webform_submission_multiple_delete_confirm')->set($this->currentUser->id(), $entities);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function execute($object = NULL) {
|
||||
$this->executeMultiple([$object]);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function access($object, AccountInterface $account = NULL, $return_as_object = FALSE) {
|
||||
/** @var \Drupal\webform\WebformSubmissionInterface $object */
|
||||
return $object->access('delete', $account, $return_as_object);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,38 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\webform\Plugin\Action;
|
||||
|
||||
use Drupal\Core\Action\ActionBase;
|
||||
use Drupal\Core\Session\AccountInterface;
|
||||
|
||||
/**
|
||||
* Makes a webform submission sticky.
|
||||
*
|
||||
* @Action(
|
||||
* id = "webform_submission_make_sticky_action",
|
||||
* label = @Translation("Star/Flag selected submission"),
|
||||
* type = "webform_submission"
|
||||
* )
|
||||
*/
|
||||
class StickyWebformSubmission extends ActionBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function execute($entity = NULL) {
|
||||
/** @var \Drupal\webform\WebformSubmissionInterface $entity */
|
||||
$entity->setSticky(TRUE)->save();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function access($object, AccountInterface $account = NULL, $return_as_object = FALSE) {
|
||||
/** @var \Drupal\webform\WebformSubmissionInterface $object */
|
||||
$result = $object->sticky->access('edit', $account, TRUE)
|
||||
->andIf($object->access('update', $account, TRUE));
|
||||
|
||||
return $return_as_object ? $result : $result->isAllowed();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,38 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\webform\Plugin\Action;
|
||||
|
||||
use Drupal\Core\Action\ActionBase;
|
||||
use Drupal\Core\Session\AccountInterface;
|
||||
|
||||
/**
|
||||
* Makes a webform submission unsticky.
|
||||
*
|
||||
* @Action(
|
||||
* id = "webform_submission_make_unsticky_action",
|
||||
* label = @Translation("Unstar/unflag selected submission"),
|
||||
* type = "webform_submission"
|
||||
* )
|
||||
*/
|
||||
class UnstickyWebformSubmission extends ActionBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function execute($entity = NULL) {
|
||||
/** @var \Drupal\webform\WebformSubmissionInterface $entity */
|
||||
$entity->setSticky(FALSE)->save();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function access($object, AccountInterface $account = NULL, $return_as_object = FALSE) {
|
||||
/** @var \Drupal\webform\WebformSubmissionInterface $object */
|
||||
$result = $object->sticky->access('edit', $account, TRUE)
|
||||
->andIf($object->access('update', $account, TRUE));
|
||||
|
||||
return $return_as_object ? $result : $result->isAllowed();
|
||||
}
|
||||
|
||||
}
|
||||
150
web/modules/contrib/webform/src/Plugin/Block/WebformBlock.php
Normal file
150
web/modules/contrib/webform/src/Plugin/Block/WebformBlock.php
Normal file
|
|
@ -0,0 +1,150 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\webform\Plugin\Block;
|
||||
|
||||
use Drupal\Core\Access\AccessResult;
|
||||
use Drupal\Core\Block\BlockBase;
|
||||
use Drupal\Core\Form\FormStateInterface;
|
||||
use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
|
||||
use Drupal\Core\Session\AccountInterface;
|
||||
use Drupal\webform\Entity\Webform;
|
||||
use Drupal\webform\WebformTokenManagerInterface;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
|
||||
/**
|
||||
* Provides a 'Webform' block.
|
||||
*
|
||||
* @Block(
|
||||
* id = "webform_block",
|
||||
* admin_label = @Translation("Webform"),
|
||||
* category = @Translation("Webform")
|
||||
* )
|
||||
*/
|
||||
class WebformBlock extends BlockBase implements ContainerFactoryPluginInterface {
|
||||
|
||||
/**
|
||||
* The module handler.
|
||||
*
|
||||
* @var \Drupal\Core\Extension\ModuleHandlerInterface
|
||||
*/
|
||||
protected $moduleHandler;
|
||||
|
||||
/**
|
||||
* The token manager.
|
||||
*
|
||||
* @var \Drupal\webform\WebformTranslationManagerInterface
|
||||
*/
|
||||
protected $tokenManager;
|
||||
|
||||
/**
|
||||
* Creates a HelpBlock instance.
|
||||
*
|
||||
* @param array $configuration
|
||||
* A configuration array containing information about the plugin instance.
|
||||
* @param string $plugin_id
|
||||
* The plugin_id for the plugin instance.
|
||||
* @param mixed $plugin_definition
|
||||
* The plugin implementation definition.
|
||||
* @param \Drupal\webform\WebformTokenManagerInterface $token_manager
|
||||
* The token manager.
|
||||
*/
|
||||
public function __construct(array $configuration, $plugin_id, $plugin_definition, WebformTokenManagerInterface $token_manager) {
|
||||
parent::__construct($configuration, $plugin_id, $plugin_definition);
|
||||
$this->tokenManager = $token_manager;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
|
||||
return new static(
|
||||
$configuration,
|
||||
$plugin_id,
|
||||
$plugin_definition,
|
||||
$container->get('webform.token_manager')
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function defaultConfiguration() {
|
||||
return [
|
||||
'webform_id' => '',
|
||||
'default_data' => '',
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function blockForm($form, FormStateInterface $form_state) {
|
||||
$form['webform_id'] = [
|
||||
'#title' => $this->t('Webform'),
|
||||
'#type' => 'entity_autocomplete',
|
||||
'#target_type' => 'webform',
|
||||
'#required' => TRUE,
|
||||
'#default_value' => $this->getWebform(),
|
||||
];
|
||||
$form['default_data'] = [
|
||||
'#title' => $this->t('Default webform submission data (YAML)'),
|
||||
'#description' => $this->t('Enter webform submission data as name and value pairs which will be used to prepopulate the selected webform. You may use tokens.'),
|
||||
'#type' => 'webform_codemirror',
|
||||
'#mode' => 'yaml',
|
||||
'#default_value' => $this->configuration['default_data'],
|
||||
];
|
||||
$form['token_tree_link'] = $this->tokenManager->buildTreeLink();
|
||||
return $form;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function blockSubmit($form, FormStateInterface $form_state) {
|
||||
$this->configuration['webform_id'] = $form_state->getValue('webform_id');
|
||||
$this->configuration['default_data'] = $form_state->getValue('default_data');
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function build() {
|
||||
return [
|
||||
'#type' => 'webform',
|
||||
'#webform' => $this->getWebform(),
|
||||
'#default_data' => $this->configuration['default_data'],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function blockAccess(AccountInterface $account) {
|
||||
$webform = $this->getWebform();
|
||||
if (!$webform || !$webform->access('submission_create', $account)) {
|
||||
return AccessResult::forbidden();
|
||||
}
|
||||
else {
|
||||
return parent::blockAccess($account);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getCacheMaxAge() {
|
||||
// Caching strategy is handled by the webform.
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get this block instance webform.
|
||||
*
|
||||
* @return \Drupal\webform\WebformInterface
|
||||
* A webform or NULL.
|
||||
*/
|
||||
protected function getWebform() {
|
||||
return Webform::load($this->configuration['webform_id']);
|
||||
}
|
||||
|
||||
}
|
||||
189
web/modules/contrib/webform/src/Plugin/Condition/Webform.php
Normal file
189
web/modules/contrib/webform/src/Plugin/Condition/Webform.php
Normal file
|
|
@ -0,0 +1,189 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\webform\Plugin\Condition;
|
||||
|
||||
use Drupal\Core\Condition\ConditionPluginBase;
|
||||
use Drupal\Core\Entity\EntityStorageInterface;
|
||||
use Drupal\Core\Form\FormStateInterface;
|
||||
use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
use Drupal\webform\Plugin\Field\FieldType\WebformEntityReferenceItem;
|
||||
|
||||
/**
|
||||
* Provides a 'Webform' condition.
|
||||
*
|
||||
* @Condition(
|
||||
* id = "webform",
|
||||
* label = @Translation("Webforms"),
|
||||
* context = {
|
||||
* "webform" = @ContextDefinition("entity:webform", label = @Translation("Webform"), required = FALSE),
|
||||
* "webform_submission" = @ContextDefinition("entity:webform_submission", label = @Translation("Webform submission"), required = FALSE),
|
||||
* "node" = @ContextDefinition("entity:node", label = @Translation("Node"), required = FALSE),
|
||||
* }
|
||||
* )
|
||||
*/
|
||||
class Webform extends ConditionPluginBase implements ContainerFactoryPluginInterface {
|
||||
|
||||
/**
|
||||
* The entity storage.
|
||||
*
|
||||
* @var \Drupal\Core\Entity\EntityStorageInterface
|
||||
*/
|
||||
protected $entityStorage;
|
||||
|
||||
/**
|
||||
* Creates a new Webform instance.
|
||||
*
|
||||
* @param \Drupal\Core\Entity\EntityStorageInterface $entity_storage
|
||||
* The entity storage.
|
||||
* @param array $configuration
|
||||
* The plugin configuration, i.e. an array with configuration values keyed
|
||||
* by configuration option name. The special key 'context' may be used to
|
||||
* initialize the defined contexts by setting it to an array of context
|
||||
* values keyed by context names.
|
||||
* @param string $plugin_id
|
||||
* The plugin_id for the plugin instance.
|
||||
* @param mixed $plugin_definition
|
||||
* The plugin implementation definition.
|
||||
*/
|
||||
public function __construct(EntityStorageInterface $entity_storage, array $configuration, $plugin_id, $plugin_definition) {
|
||||
parent::__construct($configuration, $plugin_id, $plugin_definition);
|
||||
$this->entityStorage = $entity_storage;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
|
||||
return new static(
|
||||
$container->get('entity.manager')->getStorage('webform'),
|
||||
$configuration,
|
||||
$plugin_id,
|
||||
$plugin_definition
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function buildConfigurationForm(array $form, FormStateInterface $form_state) {
|
||||
$options = [];
|
||||
$webforms = $this->entityStorage->loadMultiple();
|
||||
foreach ($webforms as $webform) {
|
||||
$options[$webform->id()] = $webform->label();
|
||||
}
|
||||
$form['webforms'] = [
|
||||
'#title' => $this->t('Webform'),
|
||||
'#description' => $this->t('Select which webforms this block should be displayed on.'),
|
||||
'#type' => 'select',
|
||||
'#options' => $options,
|
||||
'#multiple' => $options,
|
||||
'#default_value' => $this->configuration['webforms'],
|
||||
'#attached' => ['library' => ['webform/webform.element.select2']],
|
||||
'#attributes' => ['class' => ['js-webform-select2', 'webform-select2']],
|
||||
];
|
||||
|
||||
if (empty($this->configuration['context_mapping'])) {
|
||||
$form['message'] = [
|
||||
'#type' => 'webform_message',
|
||||
'#message_message' => $this->t('Please make sure to select which entities should be used to determine the current webform.'),
|
||||
'#message_type' => 'warning',
|
||||
];
|
||||
}
|
||||
|
||||
$form = parent::buildConfigurationForm($form, $form_state);
|
||||
|
||||
// Add helpful descriptions to context mapping.
|
||||
$form['context_mapping']['webform']['#description'] = $this->t("Select 'Webform from URL' to display this block, when the current request's path contains the selected webform.");
|
||||
$form['context_mapping']['webform_submission']['#title'] = $this->t('Select a @context value:', ['@context' => $this->t('webform submission')]);
|
||||
$form['context_mapping']['webform_submission']['#description'] = $this->t("Select 'Webform submission from URL' to display this block, when the current request's path contains a webform submission that was created from the selected webform.");
|
||||
$form['context_mapping']['node']['#description'] = $this->t("Select 'Node from URL' to display this block, when the current request's path contains a node that references the selected webform using a dedicated webform field or node.");
|
||||
|
||||
// Hide 'Negate the condition', which does not make sense.
|
||||
if (isset($form['negate'])) {
|
||||
$form['negate']['#access'] = FALSE;
|
||||
}
|
||||
|
||||
// Attached library to summarize configuration settings.
|
||||
$form['#attached']['library'][] = 'webform/webform.block';
|
||||
|
||||
return $form;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function validateConfigurationForm(array &$form, FormStateInterface $form_state) {
|
||||
$values = $form_state->getValues();
|
||||
if (!empty($values['webforms']) && empty(array_filter($values['context_mapping']))) {
|
||||
$form_state->setErrorByName('webforms', $this->t('Please select which entity should be used to determine the current webform.'));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function submitConfigurationForm(array &$form, FormStateInterface $form_state) {
|
||||
$this->configuration['webforms'] = array_filter($form_state->getValue('webforms'));
|
||||
parent::submitConfigurationForm($form, $form_state);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function summary() {
|
||||
if (count($this->configuration['webforms']) > 1) {
|
||||
$webforms = $this->configuration['webforms'];
|
||||
$last = array_pop($webforms);
|
||||
$webforms = implode(', ', $webforms);
|
||||
return $this->t('The webform is @webforms or @last', ['@webforms' => $webforms, '@last' => $last]);
|
||||
}
|
||||
$webform = reset($this->configuration['webforms']);
|
||||
return $this->t('The webform is @webform', ['@webform' => $webform]);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function evaluate() {
|
||||
if (empty($this->configuration['webforms']) && !$this->isNegated()) {
|
||||
return TRUE;
|
||||
}
|
||||
elseif ($webform = $this->getContextWebform()) {
|
||||
return !empty($this->configuration['webforms'][$webform->id()]);
|
||||
}
|
||||
else {
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function defaultConfiguration() {
|
||||
return ['webforms' => []] + parent::defaultConfiguration();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the webform for a defined context.
|
||||
*
|
||||
* @return null|\Drupal\webform\WebformInterface
|
||||
* The current context's webform.
|
||||
*/
|
||||
protected function getContextWebform() {
|
||||
if ($webform_submission = $this->getContextValue('webform_submission')) {
|
||||
return $webform_submission->getWebform();
|
||||
}
|
||||
if ($webform = $this->getContextValue('webform')) {
|
||||
return $webform;
|
||||
}
|
||||
if ($node = $this->getContextValue('node')) {
|
||||
$webform_field_name = WebformEntityReferenceItem::getEntityWebformFieldName($node);
|
||||
if ($webform_field_name && $node->$webform_field_name->entity) {
|
||||
return $node->$webform_field_name->entity;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show more
Reference in a new issue