class WebformOptionsCustom in Webform 6.x
Same name in this branch
- 6.x modules/webform_options_custom/src/Element/WebformOptionsCustom.php \Drupal\webform_options_custom\Element\WebformOptionsCustom
- 6.x modules/webform_options_custom/src/Entity/WebformOptionsCustom.php \Drupal\webform_options_custom\Entity\WebformOptionsCustom
- 6.x modules/webform_options_custom/src/Plugin/WebformElement/WebformOptionsCustom.php \Drupal\webform_options_custom\Plugin\WebformElement\WebformOptionsCustom
Same name and namespace in other branches
- 8.5 modules/webform_options_custom/src/Element/WebformOptionsCustom.php \Drupal\webform_options_custom\Element\WebformOptionsCustom
Provides an element for a selecting custom options from HTML or SVG markup.
Plugin annotation
@FormElement("webform_options_custom");
Hierarchy
- class \Drupal\Component\Plugin\PluginBase implements DerivativeInspectionInterface, PluginInspectionInterface
- class \Drupal\Core\Plugin\PluginBase uses DependencySerializationTrait, MessengerTrait, StringTranslationTrait
- class \Drupal\Core\Render\Element\RenderElement implements ElementInterface
- class \Drupal\Core\Render\Element\FormElement implements FormElementInterface
- class \Drupal\webform_options_custom\Element\WebformOptionsCustom implements WebformOptionsCustomInterface uses WebformCompositeFormElementTrait
- class \Drupal\Core\Render\Element\FormElement implements FormElementInterface
- class \Drupal\Core\Render\Element\RenderElement implements ElementInterface
- class \Drupal\Core\Plugin\PluginBase uses DependencySerializationTrait, MessengerTrait, StringTranslationTrait
Expanded class hierarchy of WebformOptionsCustom
1 file declares its use of WebformOptionsCustom
- WebformOptionsCustom.php in modules/
webform_options_custom/ src/ Entity/ WebformOptionsCustom.php
1 #type use of WebformOptionsCustom
- WebformOptionsCustom::getElement in modules/
webform_options_custom/ src/ Entity/ WebformOptionsCustom.php - Get the custom options element.
File
- modules/
webform_options_custom/ src/ Element/ WebformOptionsCustom.php, line 25
Namespace
Drupal\webform_options_custom\ElementView source
class WebformOptionsCustom extends FormElement implements WebformOptionsCustomInterface {
use WebformCompositeFormElementTrait;
/**
* The properties of the element.
*
* @var array
*/
protected static $properties = [
'#title',
'#options',
'#default_value',
'#multiple',
'#attributes',
'#empty_option',
'#empty_value',
'#select2',
'#chosen',
// NOTE:
// Choices is not supported by custom options because of <option> being
// removed inside the <select>.
// @see https://github.com/jshjohnson/Choices/issues/601
'#placeholder',
'#help_display',
'#size',
'#required',
'#required_error',
];
/**
* {@inheritdoc}
*/
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,
];
}
/**
* {@inheritdoc}
*/
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;
}
}
/**
* Processes an 'other' element.
*
* See select list webform element for select list properties.
*
* @see \Drupal\Core\Render\Element\Select
*/
public static function processWebformOptionsCustom(&$element, FormStateInterface $form_state, &$complete_form) {
// Load config entity and set the element's #options and #template.
static::setTemplateOptions($element);
// Sanitize option descriptions which may have been altered.
// Note: Option text is escaped via JavaScript.
// @see webform_options_custom.element.js#initializeTemplateTooltip
$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);
}
}
// Get inline template context.
$template_context = WebformArrayHelper::removePrefix($element) + [
'descriptions' => $descriptions,
];
$element['#tree'] = TRUE;
// Select menu.
$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));
// Apply #parents to select element.
if (isset($element['#parents'])) {
$element['select']['#parents'] = array_merge($element['#parents'], [
'select',
]);
}
// Initialize the select to allow for webform enhancements.
/** @var \Drupal\webform\Plugin\WebformElementManagerInterface $element_manager */
$element_manager = \Drupal::service('plugin.manager.webform.element');
$element_manager
->buildElement($element['select'], $complete_form, $form_state);
if (preg_match('/(\\{\\{|\\{%)/', $element['#template'])) {
// Build template using Twig when Twig syntax is found.
$element['template'] = [
'#type' => 'inline_template',
'#template' => $element['#template'],
'#context' => $template_context,
'#prefix' => '<div class="webform-options-custom-template">',
'#suffic' => '</div>',
];
}
else {
// Build template using markup.
$element['template'] = [
'#markup' => Markup::create($element['#template']),
'#prefix' => '<div class="webform-options-custom-template">',
'#suffic' => '</div>',
];
}
// Set classes.
$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;
}
// Apply the element id to the wrapper so that inline form errors point
// to the correct element.
$element['#attributes']['id'] = $element['#id'];
// Set SVG fill, zoom, tooltip, and show/hide select.
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;
}
// Set descriptions.
if ($descriptions) {
$element['#attributes']['data-descriptions'] = Json::encode($descriptions);
}
// Remove options to prevent option validation on the element.
unset($element['#options']);
// Add validate callback.
$element += [
'#element_validate' => [],
];
array_unshift($element['#element_validate'], [
get_called_class(),
'validateWebformOptionsCustom',
]);
// Attach libraries.
$element['#attached']['library'][] = 'webform_options_custom/webform_options_custom.element';
if ($element['#zoom']) {
$element['#attached']['library'][] = 'webform_options_custom/libraries.svg-pan-zoom';
}
// Process states.
WebformFormHelper::processStates($element, '#wrapper_attributes');
return $element;
}
/**
* Validates an other element.
*/
public static function validateWebformOptionsCustom(&$element, FormStateInterface $form_state, &$complete_form) {
$value = NestedArray::getValue($form_state
->getValues(), $element['select']['#parents']);
// Determine if the element has multiple values.
$is_multiple = empty($element['#multiple']) ? FALSE : TRUE;
// Determine if the return value is empty.
if ($is_multiple) {
$is_empty = empty($value) ? TRUE : FALSE;
}
else {
$is_empty = $value === '' || $value === NULL ? TRUE : FALSE;
}
// Validate on elements with #access.
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);
}
/****************************************************************************/
// Helper methods.
/****************************************************************************/
/**
* Set a custom options element #options property.
*
* @param array $element
* A custom options element.
*/
public static function setOptions(array &$element) {
// Do nothing.
}
/**
* Set a custom options element #options property.
*
* @param array $element
* A custom options element.
*/
public static function setTemplateOptions(array &$element) {
if (isset($element['#_options_custom'])) {
return;
}
$element['#_options_custom'] = TRUE;
// Set options. Used by entity references.
static::setOptions($element);
// Load custom options from config entity.
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'];
}
}
// Set default properties.
$element += [
'#options' => [],
'#value_attributes' => 'data-option-value,data-value,data-id,id',
'#text_attributes' => 'data-option-text,data-text,data-name,name,title',
];
// Get options.
$options =& $element['#options'];
// Build options by text look up.
$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,
];
}
// Get option value and text attributes.
$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;
}
// Combine text and value attributes into an Xpath query that finds all
// DOM element which contain any of the attributes.
$css_attributes = array_map(function ($value) {
return 'descendant-or-self::*[@' . $value . ']';
}, $custom_attributes);
$xpath_expression = implode(' | ', $css_attributes);
// Remove XML tag from SVG file.
$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) {
/** @var \DOMNode $attribute_node */
$dom_attributes[$attribute_name] = $attribute_node->nodeValue;
}
$dom_attributes += [
$value_attribute_name => '',
$text_attribute_name => '',
];
// Get value and text attribute.
$option_value = $dom_attributes[$value_attribute_name];
$option_text = $dom_attributes[$text_attribute_name];
// Set missing options value based on options text.
if ($option_value === '' && $option_text !== '') {
// Look up options value using the option's text.
if (isset($options_by_text[$option_text])) {
$option_value = $options_by_text[$option_text]['value'];
}
else {
$option_value = $option_text;
}
}
// Append value and text to the options array.
$options += [
$option_value => $option_text ?: $option_value,
];
// Always set the data-option-value attribute.
// Note: The select menu's option text is the canonical source for
// the option text.
$dom_node
->setAttribute('data-option-value', $option_value);
}
// Set template with tweaked or additional attributes.
$element['#template'] = $xml_tag . Html::serialize($dom);
}
}
Members
Name | Modifiers | Type | Description | Overrides |
---|---|---|---|---|
DependencySerializationTrait:: |
protected | property | ||
DependencySerializationTrait:: |
protected | property | ||
DependencySerializationTrait:: |
public | function | 2 | |
DependencySerializationTrait:: |
public | function | 2 | |
FormElement:: |
public static | function | Adds autocomplete functionality to elements. | |
FormElement:: |
public static | function | #process callback for #pattern form element property. | |
FormElement:: |
public static | function | #element_validate callback for #pattern form element property. | |
MessengerTrait:: |
protected | property | The messenger. | 27 |
MessengerTrait:: |
public | function | Gets the messenger. | 27 |
MessengerTrait:: |
public | function | Sets the messenger. | |
PluginBase:: |
protected | property | Configuration information passed into the plugin. | 1 |
PluginBase:: |
protected | property | The plugin implementation definition. | 1 |
PluginBase:: |
protected | property | The plugin_id. | |
PluginBase:: |
constant | A string which is used to separate base plugin IDs from the derivative ID. | ||
PluginBase:: |
public | function |
Gets the base_plugin_id of the plugin instance. Overrides DerivativeInspectionInterface:: |
|
PluginBase:: |
public | function |
Gets the derivative_id of the plugin instance. Overrides DerivativeInspectionInterface:: |
|
PluginBase:: |
public | function |
Gets the definition of the plugin implementation. Overrides PluginInspectionInterface:: |
2 |
PluginBase:: |
public | function |
Gets the plugin_id of the plugin instance. Overrides PluginInspectionInterface:: |
|
PluginBase:: |
public | function | Determines if the plugin is configurable. | |
PluginBase:: |
public | function | Constructs a \Drupal\Component\Plugin\PluginBase object. | 98 |
RenderElement:: |
public static | function | Adds Ajax information about an element to communicate with JavaScript. | |
RenderElement:: |
public static | function | Adds members of this group as actual elements for rendering. | |
RenderElement:: |
public static | function | Form element processing handler for the #ajax form property. | 1 |
RenderElement:: |
public static | function | Arranges elements into groups. | |
RenderElement:: |
public static | function |
Sets a form element's class attribute. Overrides ElementInterface:: |
|
StringTranslationTrait:: |
protected | property | The string translation service. | 4 |
StringTranslationTrait:: |
protected | function | Formats a string containing a count of items. | |
StringTranslationTrait:: |
protected | function | Returns the number of plurals supported by a given language. | |
StringTranslationTrait:: |
protected | function | Gets the string translation service. | |
StringTranslationTrait:: |
public | function | Sets the string translation service to use. | 2 |
StringTranslationTrait:: |
protected | function | Translates a string to the current language or to a given language. | |
WebformCompositeFormElementTrait:: |
public static | function | Adds form element theming to an element if its title or description is set. | 1 |
WebformOptionsCustom:: |
protected static | property | The properties of the element. | |
WebformOptionsCustom:: |
public | function |
Returns the element properties for this element. Overrides ElementInterface:: |
|
WebformOptionsCustom:: |
public static | function | Processes an 'other' element. | |
WebformOptionsCustom:: |
public static | function | Set a custom options element #options property. | |
WebformOptionsCustom:: |
public static | function |
Set a custom options element #options property. Overrides WebformOptionsCustomInterface:: |
1 |
WebformOptionsCustom:: |
public static | function | Validates an other element. | |
WebformOptionsCustom:: |
public static | function |
Determines how user input is mapped to an element's #value property. Overrides FormElement:: |