View source
<?php
namespace Drupal\webform_options_custom\Element;
use Drupal\Component\Serialization\Json;
use Drupal\Component\Utility\Html;
use Drupal\Component\Utility\NestedArray;
use Drupal\Component\Utility\Xss;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Render\Element;
use Drupal\Core\Render\Element\FormElement;
use Drupal\Core\Render\Markup;
use Drupal\webform\Element\WebformCompositeFormElementTrait;
use Drupal\webform\Utility\WebformArrayHelper;
use Drupal\webform\Utility\WebformElementHelper;
use Drupal\webform\Utility\WebformOptionsHelper;
use Drupal\webform_options_custom\Entity\WebformOptionsCustom as WebformOptionsCustomEntity;
class WebformOptionsCustom extends FormElement implements WebformOptionsCustomInterface {
use WebformCompositeFormElementTrait;
protected static $properties = [
'#title',
'#options',
'#default_value',
'#multiple',
'#attributes',
'#empty_option',
'#empty_value',
'#select2',
'#chosen',
'#placeholder',
'#help_display',
'#size',
'#required',
'#required_error',
];
public function getInfo() {
$class = get_class($this);
return [
'#input' => TRUE,
'#process' => [
[
$class,
'processWebformOptionsCustom',
],
[
$class,
'processAjaxForm',
],
],
'#pre_render' => [
[
$class,
'preRenderWebformCompositeFormElement',
],
],
'#options_custom' => NULL,
'#options' => [],
'#template' => '',
'#value_attributes' => 'data-option-value,data-value,data-id,id',
'#text_attributes' => 'data-option-text,data-text,data-name,name,title',
'#fill' => TRUE,
'#zoom' => FALSE,
'#tooltip' => FALSE,
'#show_select' => TRUE,
];
}
public static function valueCallback(&$element, $input, FormStateInterface $form_state) {
$element += [
'#default_value' => '',
];
if ($input === FALSE) {
return [
'value' => $element['#default_value'],
];
}
else {
if (isset($input['select'])) {
$input['value'] = $input['select'];
}
return $input;
}
}
public static function processWebformOptionsCustom(&$element, FormStateInterface $form_state, &$complete_form) {
static::setTemplateOptions($element);
$descriptions = [];
foreach ($element['#options'] as $option_value => $option_text) {
if (WebformOptionsHelper::hasOptionDescription($option_text)) {
list($option_text, $option_description) = WebformOptionsHelper::splitOption($option_text);
$element['#options'][$option_value] = $option_text;
$descriptions[$option_value] = Xss::filterAdmin($option_description);
}
}
$template_context = WebformArrayHelper::removePrefix($element) + [
'descriptions' => $descriptions,
];
$element['#tree'] = TRUE;
$element['select'] = [
'#type' => 'select',
'#options' => $element['#options'],
'#title' => $element['#title'],
'#webform_element' => TRUE,
'#title_display' => 'invisible',
'#error_no_message' => TRUE,
];
$properties = static::$properties;
$element['select'] += array_intersect_key($element, array_combine($properties, $properties));
if (isset($element['#parents'])) {
$element['select']['#parents'] = array_merge($element['#parents'], [
'select',
]);
}
$element_manager = \Drupal::service('plugin.manager.webform.element');
$element_manager
->buildElement($element['select'], $complete_form, $form_state);
if (preg_match('/(\\{\\{|\\{%)/', $element['#template'])) {
$element['template'] = [
'#type' => 'inline_template',
'#template' => $element['#template'],
'#context' => $template_context,
'#prefix' => '<div class="webform-options-custom-template">',
'#suffic' => '</div>',
];
}
else {
$element['template'] = [
'#markup' => Markup::create($element['#template']),
'#prefix' => '<div class="webform-options-custom-template">',
'#suffic' => '</div>',
];
}
$element['#attributes']['class'][] = 'js-webform-options-custom';
$element['#attributes']['class'][] = 'webform-options-custom';
if (!empty($element['#options_custom'])) {
$webform_options_custom_class = Html::getClass($element['#options_custom']);
$element['#attributes']['class'][] = 'js-webform-options-custom--' . $webform_options_custom_class;
$element['#attributes']['class'][] = 'webform-options-custom--' . $webform_options_custom_class;
}
$element['#attributes']['id'] = $element['#id'];
if ($element['#fill']) {
$element['#attributes']['data-fill'] = TRUE;
}
if ($element['#zoom']) {
$element['#attributes']['data-zoom'] = TRUE;
}
if ($element['#tooltip']) {
$element['#attributes']['data-tooltip'] = TRUE;
}
if (empty($element['#show_select'])) {
$element['#attributes']['data-select-hidden'] = TRUE;
}
if ($descriptions) {
$element['#attributes']['data-descriptions'] = Json::encode($descriptions);
}
unset($element['#options']);
$element += [
'#element_validate' => [],
];
array_unshift($element['#element_validate'], [
get_called_class(),
'validateWebformOptionsCustom',
]);
$element['#attached']['library'][] = 'webform_options_custom/webform_options_custom.element';
if ($element['#zoom']) {
$element['#attached']['library'][] = 'webform_options_custom/libraries.svg-pan-zoom';
}
webform_process_states($element, '#wrapper_attributes');
return $element;
}
public static function validateWebformOptionsCustom(&$element, FormStateInterface $form_state, &$complete_form) {
$value = NestedArray::getValue($form_state
->getValues(), $element['select']['#parents']);
$is_multiple = empty($element['#multiple']) ? FALSE : TRUE;
if ($is_multiple) {
$is_empty = empty($value) ? TRUE : FALSE;
}
else {
$is_empty = $value === '' || $value === NULL ? TRUE : FALSE;
}
if (Element::isVisibleElement($element) && !empty($element['#required']) && $is_empty) {
WebformElementHelper::setRequiredError($element, $form_state);
}
$form_state
->setValueForElement($element['select'], NULL);
$element['#value'] = $value;
$form_state
->setValueForElement($element, $value);
}
public static function setOptions(array &$element) {
}
public static function setTemplateOptions(array &$element) {
if (isset($element['#_options_custom'])) {
return;
}
$element['#_options_custom'] = TRUE;
static::setOptions($element);
if (!empty($element['#options_custom'])) {
$webform_option_custom = WebformOptionsCustomEntity::load($element['#options_custom']);
if ($webform_option_custom) {
$custom_element = $webform_option_custom
->getElement();
$element += $custom_element;
$element['#options'] += $custom_element['#options'];
}
}
$element += [
'#options' => [],
'#value_attributes' => 'data-option-value,data-value,data-id,id',
'#text_attributes' => 'data-option-text,data-text,data-name,name,title',
];
$options =& $element['#options'];
$options_by_text = [];
foreach ($options as $option_value => $option_text) {
$option_description = '';
if (WebformOptionsHelper::hasOptionDescription($option_text)) {
list($option_text, $option_description) = WebformOptionsHelper::splitOption($option_text);
}
$options_by_text[$option_text] = [
'value' => $option_value,
'text' => $option_text,
'description' => $option_description,
];
}
$value_attribute_name = NULL;
if ($element['#value_attributes']) {
$value_attributes = preg_split('/\\s*,\\s*/', trim($element['#value_attributes']));
foreach ($value_attributes as $value_attribute) {
if (strpos($element['#template'], $value_attribute) !== FALSE) {
$value_attribute_name = $value_attribute;
break;
}
}
}
$text_attribute_name = NULL;
if ($element['#text_attributes']) {
$text_attributes = preg_split('/\\s*,\\s*/', trim($element['#text_attributes']));
foreach ($text_attributes as $text_attribute) {
if (strpos($element['#template'], $text_attribute) !== FALSE) {
$text_attribute_name = $text_attribute;
break;
}
}
}
$custom_attributes = [];
if ($value_attribute_name) {
$custom_attributes[] = $value_attribute_name;
}
if ($text_attribute_name) {
$custom_attributes[] = $text_attribute_name;
}
if (empty($custom_attributes)) {
return;
}
$css_attributes = array_map(function ($value) {
return 'descendant-or-self::*[@' . $value . ']';
}, $custom_attributes);
$xpath_expression = implode(' | ', $css_attributes);
$xml_tag = NULL;
$template = $element['#template'];
if (preg_match('/<\\?xml[^>]+\\?>\\s+/', $element['#template'], $match)) {
$xml_tag = $match[0];
$template = str_replace($xml_tag, '', $template);
}
$dom = Html::load($template);
$xpath = new \DOMXPath($dom);
foreach ($xpath
->query($xpath_expression) as $dom_node) {
if (in_array($dom_node->tagName, [
'svg',
])) {
continue;
}
$dom_attributes = [];
foreach ($dom_node->attributes as $attribute_name => $attribute_node) {
$dom_attributes[$attribute_name] = $attribute_node->nodeValue;
}
$dom_attributes += [
$value_attribute_name => '',
$text_attribute_name => '',
];
$option_value = $dom_attributes[$value_attribute_name];
$option_text = $dom_attributes[$text_attribute_name];
if ($option_value === '' && $option_text !== '') {
if (isset($options_by_text[$option_text])) {
$option_value = $options_by_text[$option_text]['value'];
}
else {
$option_value = $option_text;
}
}
$options += [
$option_value => $option_text ?: $option_value,
];
$dom_node
->setAttribute('data-option-value', $option_value);
}
$element['#template'] = $xml_tag . Html::serialize($dom);
}
}