Select.php 8.87 KB
Newer Older
1
2
3
4
5
<?php

namespace Drupal\webform\Plugin\WebformElement;

use Drupal\Core\Form\FormStateInterface;
6
use Drupal\webform\Utility\WebformArrayHelper;
7
8
9
10
11
12
13
14
15
use Drupal\webform\WebformSubmissionInterface;

/**
 * Provides a 'select' element.
 *
 * @WebformElement(
 *   id = "select",
 *   api = "https://api.drupal.org/api/drupal/core!lib!Drupal!Core!Render!Element!Select.php/class/Select",
 *   label = @Translation("Select"),
16
 *   description = @Translation("Provides a form element for a drop-down menu or scrolling selection box."),
17
18
19
20
21
22
23
24
 *   category = @Translation("Options elements"),
 * )
 */
class Select extends OptionsBase {

  /**
   * {@inheritdoc}
   */
25
  protected function defineDefaultProperties() {
26
    $properties = [
27
28
      // Options settings.
      'multiple' => FALSE,
29
      'multiple_error' => '',
30
31
      'empty_option' => '',
      'empty_value' => '',
32
      'sort_options' => FALSE,
33
      'select2' => FALSE,
34
      'choices' => FALSE,
35
      'chosen' => FALSE,
36
      'placeholder' => '',
37
      'help_display' => '',
38
      'size' => '',
39
    ] + parent::defineDefaultProperties();
40
    return $properties;
41
42
  }

43
  /* ************************************************************************ */
44

45
46
47
48
49
50
51
  /**
   * {@inheritdoc}
   */
  public function supportsMultipleValues() {
    return TRUE;
  }

52
53
54
  /**
   * {@inheritdoc}
   */
55
  public function prepare(array &$element, WebformSubmissionInterface $webform_submission = NULL) {
56
57
58
59
60
61
62
63
64
65
66
67
    $config = $this->configFactory->get('webform.settings');

    // Always include empty option.
    // Note: #multiple select menu does support empty options.
    // @see \Drupal\Core\Render\Element\Select::processSelect
    if (!isset($element['#empty_option']) && empty($element['#multiple'])) {
      $required = isset($element['#states']['required']) ? TRUE : !empty($element['#required']);
      $empty_option = $required
        ? ($config->get('element.default_empty_option_required') ?: $this->t('- Select -'))
        : ($config->get('element.default_empty_option_optional') ?: $this->t('- None -'));
      if ($config->get('element.default_empty_option')) {
        $element['#empty_option'] = $empty_option;
68
      }
69
      // Copied from: \Drupal\Core\Render\Element\Select::processSelect.
70
71
      elseif (($required && !isset($element['#default_value'])) || isset($element['#empty_value'])) {
        $element['#empty_option'] = $empty_option;
72
      }
73
74
    }

75
76
77
78
79
    // If select2, choices, or chosen is not available,
    // see if we can use the alternative.
    $select2_exists = $this->librariesManager->isIncluded('jquery.select2');
    $choices_exists = $this->librariesManager->isIncluded('choices');
    $chosen_exists = $this->librariesManager->isIncluded('jquery.chosen');
80
81
82
83
84
    $default_select = ($select2_exists ? '#select2' :
      ($choices_exists ? '#choices' :
        ($chosen_exists ? '#chosen' : NULL)
      )
    );
85
86
    if (isset($element['#select2']) && !$select2_exists) {
      $element['#' . $default_select] = TRUE;
87
    }
88
89
90
91
92
    elseif (isset($element['#choices']) && !$choices_exists) {
      $element['#' . $default_select] = TRUE;
    }
    elseif (isset($element['#chosen']) && !$chosen_exists) {
      $element['#' . $default_select] = TRUE;
93
    }
94

95
96
    // Enhance select element using select2, chosen, or choices.
    if (isset($element['#select2']) && $select2_exists) {
97
98
99
100
      $element['#attached']['library'][] = 'webform/webform.element.select2';
      $element['#attributes']['class'][] = 'js-webform-select2';
      $element['#attributes']['class'][] = 'webform-select2';
    }
101
102
103
104
105
106
    elseif (isset($element['#choices']) && $choices_exists) {
      $element['#attached']['library'][] = 'webform/webform.element.choices';
      $element['#attributes']['class'][] = 'js-webform-choices';
      $element['#attributes']['class'][] = 'webform-choices';
    }
    elseif (isset($element['#chosen']) && $chosen_exists) {
107
108
109
110
111
      $element['#attached']['library'][] = 'webform/webform.element.chosen';
      $element['#attributes']['class'][] = 'js-webform-chosen';
      $element['#attributes']['class'][] = 'webform-chosen';
    }

112
    // Set placeholder as data attributes for select2, choices or chosen.
113
    if (!empty($element['#placeholder'])) {
114
115
      $element['#attributes']['data-placeholder'] = $element['#placeholder'];
    }
116
117
118
119
    // Set limit as data attributes for select2, choices or chosen.
    if (isset($element['#multiple']) && $element['#multiple'] > 1) {
      $element['#attributes']['data-limit'] = $element['#multiple'];
    }
120

121
122
123
    // Attach library which allows options to be disabled via JavaScript.
    $element['#attached']['library'][] = 'webform/webform.element.select';

124
    parent::prepare($element, $webform_submission);
125
126
127
128
129
130
131
  }

  /**
   * {@inheritdoc}
   */
  public function form(array $form, FormStateInterface $form_state) {
    $form = parent::form($form, $form_state);
132

133
    // Select2, Chosen, and/or Choices enhancements.
134
    // @see \Drupal\webform\Plugin\WebformElement\WebformCompositeBase::form
135
136
137
138
    $select2_exists = $this->librariesManager->isIncluded('jquery.select2');
    $choices_exists = $this->librariesManager->isIncluded('choices');
    $chosen_exists = $this->librariesManager->isIncluded('jquery.chosen');

139
140
    $form['options']['select2'] = [
      '#type' => 'checkbox',
141
      '#title' => $this->t('Select2'),
142
      '#description' => $this->t('Replace select element with jQuery <a href=":href">Select2</a> select box.', [':href' => 'https://select2.github.io/']),
143
      '#return_value' => TRUE,
144
145
146
147
148
      '#states' => [
        'disabled' => [
          ':input[name="properties[chosen]"]' => ['checked' => TRUE],
        ],
      ],
149
    ];
150
    if (!$select2_exists) {
151
152
      $form['options']['select2']['#access'] = FALSE;
    }
153
154
155
    $form['options']['choices'] = [
      '#type' => 'checkbox',
      '#title' => $this->t('Choices'),
156
      '#description' => $this->t('Replace select element with <a href=":href">Choice.js</a> select box.', [':href' => 'https://choices-js.github.io/Choices/']),
157
158
159
160
161
162
163
164
165
166
      '#return_value' => TRUE,
      '#states' => [
        'disabled' => [
          ':input[name="properties[select2]"]' => ['checked' => TRUE],
        ],
      ],
    ];
    if (!$choices_exists) {
      $form['options']['choices']['#access'] = FALSE;
    }
167
168
169
    $form['options']['chosen'] = [
      '#type' => 'checkbox',
      '#title' => $this->t('Chosen'),
170
      '#description' => $this->t('Replace select element with jQuery <a href=":href">Chosen</a> select box.', [':href' => 'https://harvesthq.github.io/chosen/']),
171
172
173
174
175
176
177
      '#return_value' => TRUE,
      '#states' => [
        'disabled' => [
          ':input[name="properties[select2]"]' => ['checked' => TRUE],
        ],
      ],
    ];
178
    if (!$chosen_exists) {
179
180
      $form['options']['chosen']['#access'] = FALSE;
    }
181
182
183
184
185
186
187
188
189
190
191
192
193
194
    if (($select2_exists + $chosen_exists + $choices_exists) > 1) {
      $select_libraries = [];
      if ($select2_exists) {
        $select_libraries[] = $this->t('Select2');
      }
      if ($choices_exists) {
        $select_libraries[] = $this->t('Choices');
      }
      if ($chosen_exists) {
        $select_libraries[] = $this->t('Chosen');
      }
      $t_args = [
        '@libraries' => WebformArrayHelper::toString($select_libraries),
      ];
195
196
197
      $form['options']['select_message'] = [
        '#type' => 'webform_message',
        '#message_type' => 'warning',
198
        '#message_message' => $this->t('@libraries provide very similar functionality, only one should be enabled.', $t_args),
199
200
201
        '#access' => TRUE,
      ];
    }
202
203
204
205

    // Add states to placeholder if custom library is supported and the
    // select menu supports multiple values.
    $placeholder_states = [];
206
    if ($select2_exists) {
207
208
      $placeholder_states[] = [':input[name="properties[select2]"]' => ['checked' => TRUE]];
    }
209
    if ($chosen_exists) {
210
211
212
213
214
      if (isset($form['form']['placeholder']['#states']['visible'])) {
        $placeholder_states[] = 'or';
      }
      $placeholder_states[] = [':input[name="properties[chosen]"]' => ['checked' => TRUE]];
    }
215
216
217
218
219
220
    if ($choices_exists) {
      if (isset($form['form']['placeholder']['#states']['visible'])) {
        $placeholder_states[] = 'or';
      }
      $placeholder_states[] = [':input[name="properties[choices]"]' => ['checked' => TRUE]];
    }
221
222
223
224
225
226
    if ($placeholder_states) {
      $form['form']['placeholder']['#states']['visible'] = [
        [
        ':input[name="properties[multiple][container][cardinality]"]' => ['value' => 'number'],
        ':input[name="properties[multiple][container][cardinality_number]"]' => ['!value' => 1],
        ],
227
        $placeholder_states,
228
229
230
231
232
233
      ];
    }
    else {
      $form['form']['placeholder']['#access'] = FALSE;
    }

234
235
236
237
238
    // Update multiple select size property.
    $form['form']['size_container']['size']['#description'] = $this->t('Specifies the number of visible options.');
    $form['form']['size_container']['#states'] = [
      'visible' => [
        ':input[name="properties[multiple][container][cardinality_number]"]' => ['!value' => 1],
239
      ],
240
241
    ];

242
243
244
245
    return $form;
  }

}