Updated all the contrib modules to their latest versions.
[yaffs-website] / web / modules / contrib / entityqueue / src / Plugin / Field / FieldWidget / EntityqueueDragtableWidget.php
1 <?php
2
3 namespace Drupal\entityqueue\Plugin\Field\FieldWidget;
4
5 use Drupal\Component\Utility\Html;
6 use Drupal\Component\Utility\NestedArray;
7 use Drupal\Core\Entity\Element\EntityAutocomplete;
8 use Drupal\Core\Field\FieldItemListInterface;
9 use Drupal\Core\Field\FieldStorageDefinitionInterface;
10 use Drupal\Core\Field\Plugin\Field\FieldWidget\EntityReferenceAutocompleteWidget;
11 use Drupal\Core\Form\FormStateInterface;
12
13 /**
14  * Plugin implementation of the 'entityqueue_dragtable' widget.
15  *
16  * @FieldWidget(
17  *   id = "entityqueue_dragtable",
18  *   label = @Translation("Autocomplete (draggable table) - Experimental"),
19  *   description = @Translation("An autocomplete text field with a draggable table."),
20  *   field_types = {
21  *     "entity_reference"
22  *   }
23  * )
24  */
25 class EntityqueueDragtableWidget extends EntityReferenceAutocompleteWidget {
26
27   /**
28    * The unique HTML ID of the widget's wrapping element.
29    *
30    * @var string
31    */
32   protected $wrapperId;
33
34   /**
35    * {@inheritdoc}
36    */
37   public static function defaultSettings() {
38     return [
39       'link_to_entity' => FALSE,
40     ] + parent::defaultSettings();
41   }
42
43   /**
44    * {@inheritdoc}
45    */
46   public function settingsForm(array $form, FormStateInterface $form_state) {
47     $elements = parent::settingsForm($form, $form_state);
48
49     $elements['link_to_entity'] = [
50       '#type' => 'checkbox',
51       '#title' => $this->t('Link label to the referenced entity'),
52       '#default_value' => $this->getSetting('link'),
53     ];
54
55     return $elements;
56   }
57
58   /**
59    * {@inheritdoc}
60    */
61   public function settingsSummary() {
62     $summary = parent::settingsSummary();
63
64     $settings = $this->getSettings();
65     if (!empty($settings['link_to_entity'])) {
66       $summary[] = $this->t('Link to the referenced entity');
67     }
68
69     return $summary;
70   }
71
72   /**
73    * {@inheritdoc}
74    */
75   public function formElement(FieldItemListInterface $items, $delta, array $element, array &$form, FormStateInterface $form_state) {
76     $field_name = $this->fieldDefinition->getName();
77     $parents = $form['#parents'];
78     $referenced_entities = $items->referencedEntities();
79
80     if (isset($referenced_entities[$delta])) {
81       if ($this->getSetting('link_to_entity') && !$referenced_entities[$delta]->isNew()) {
82         $entity_label = $referenced_entities[$delta]->toLink()->toString();
83       }
84       else {
85         $entity_label = $referenced_entities[$delta]->label();
86       }
87       $id_prefix = implode('-', array_merge($parents, [$field_name, $delta]));
88
89       $element += [
90         '#type' => 'container',
91         '#attributes' => ['class' => ['form--inline']],
92         'target_id' => [
93           '#type' => 'item',
94           '#markup' => $entity_label,
95           '#default_value' => !$referenced_entities[$delta]->isNew() ? $referenced_entities[$delta]->id() : NULL,
96         ],
97         'entity' => [
98           '#type' => 'value',
99           '#default_value' => $referenced_entities[$delta],
100         ],
101         'remove' => [
102           '#type' => 'submit',
103           '#name' => strtr($id_prefix, '-', '_') . '_remove',
104           '#value' => $this->t('Remove'),
105           '#attributes' => ['class' => ['remove-item-submit', 'align-right']],
106           '#submit' => [[get_class($this), 'removeSubmit']],
107           '#ajax' => [
108             'callback' => [get_class($this), 'getWidgetElementAjax'],
109             'wrapper' => $this->getWrapperId(),
110             'effect' => 'fade',
111           ],
112         ],
113       ];
114     }
115
116     return $element;
117   }
118
119   /**
120    * {@inheritdoc}
121    */
122   protected function formMultipleElements(FieldItemListInterface $items, array &$form, FormStateInterface $form_state) {
123     $field_name = $this->fieldDefinition->getName();
124     $cardinality = $this->fieldDefinition->getFieldStorageDefinition()->getCardinality();
125     $parents = $form['#parents'];
126
127     // Assign a unique identifier to each widget.
128     $id_prefix = implode('-', array_merge($parents, [$field_name]));
129     $wrapper_id = Html::getUniqueId($id_prefix . '-add-more-wrapper');
130     $this->setWrapperId($wrapper_id);
131
132     // Load the items for form rebuilds from the field state as they might not
133     // be in $form_state->getValues() because of validation limitations. Also,
134     // they are only passed in as $items when editing existing entities.
135     $field_state = static::getWidgetState($parents, $field_name, $form_state);
136     if (isset($field_state['items'])) {
137       $items->setValue($field_state['items']);
138     }
139
140     // Lower the 'items_count' field state property in order to prevent the
141     // parent implementation to append an extra empty item.
142     if ($cardinality == FieldStorageDefinitionInterface::CARDINALITY_UNLIMITED) {
143       $field_state['items_count'] = (count($items) > 1) ? count($items) - 1 : 0;
144       static::setWidgetState($parents, $field_name, $form_state, $field_state);
145     }
146
147     $elements = parent::formMultipleElements($items, $form, $form_state);
148
149     if ($elements) {
150       if (isset($elements['add_more'])) {
151         // Update the HTML wrapper ID with the one generated by us.
152         $elements['#prefix'] = '<div id="' . $this->getWrapperId() . '">';
153
154         $add_more_button = $elements['add_more'];
155         $add_more_button['#value'] = $this->t('Add item');
156         $add_more_button['#ajax']['callback'] = [get_class($this), 'getWidgetElementAjax'];
157         $add_more_button['#ajax']['wrapper'] = $this->getWrapperId();
158
159         $elements['add_more'] = [
160           '#type' => 'container',
161           '#tree' => TRUE,
162           '#attributes' => ['class' => ['form--inline']],
163           'new_item' => parent::formElement($items, -1, [], $form, $form_state),
164           'submit' => $add_more_button,
165         ];
166       }
167     }
168
169     return $elements;
170   }
171
172   /**
173    * {@inheritdoc}
174    */
175   public static function getWidgetElementAjax(array $form, FormStateInterface $form_state) {
176     $button = $form_state->getTriggeringElement();
177
178     // Go two levels up in the form, to the widgets container.
179     $element = NestedArray::getValue($form, array_slice($button['#array_parents'], 0, -2));
180
181     // Ensure the widget allows adding additional items.
182     if ($element['#cardinality'] != FieldStorageDefinitionInterface::CARDINALITY_UNLIMITED) {
183       return;
184     }
185
186     // Add a DIV around the delta receiving the Ajax effect.
187     $delta = $element['#max_delta'];
188     $element[$delta]['#prefix'] = '<div class="ajax-new-content">' . (isset($element[$delta]['#prefix']) ? $element[$delta]['#prefix'] : '');
189     $element[$delta]['#suffix'] = (isset($element[$delta]['#suffix']) ? $element[$delta]['#suffix'] : '') . '</div>';
190
191     return $element;
192   }
193
194   /**
195    * {@inheritdoc}
196    */
197   public static function addMoreSubmit(array $form, FormStateInterface $form_state) {
198     // During the form rebuild, formElement() will create field item widget
199     // elements using re-indexed deltas, so clear out FormState::$input to
200     // avoid a mismatch between old and new deltas. The rebuilt elements will
201     // have #default_value set appropriately for the current state of the field,
202     // so nothing is lost in doing this.
203     $button = $form_state->getTriggeringElement();
204     $parents = array_slice($button['#parents'], 0, -2);
205     NestedArray::setValue($form_state->getUserInput(), $parents, NULL);
206
207     // Go two levels up in the form, to the widgets container.
208     $element = NestedArray::getValue($form, array_slice($button['#array_parents'], 0, -2));
209     $field_name = $element['#field_name'];
210     $parents = $element['#field_parents'];
211
212     $submitted_values = NestedArray::getValue($form_state->getValues(), array_slice($button['#parents'], 0, -2));
213
214     // Check submitted values for empty items.
215     $new_values = [];
216     foreach ($submitted_values as $delta => $submitted_value) {
217       if ($delta !== 'add_more' && (isset($submitted_value['target_id']) || isset($submitted_value['entity']))) {
218         $new_values[] = $submitted_value;
219       }
220
221       if ($delta === 'add_more' && (isset($submitted_value['new_item']['target_id']) || isset($submitted_value['new_item']['entity']))) {
222         $new_values[] = $submitted_value['new_item'];
223       }
224     }
225
226     // Re-index deltas after removing empty items.
227     $submitted_values = array_values($new_values);
228
229     // Update form_state values.
230     NestedArray::setValue($form_state->getValues(), array_slice($button['#parents'], 0, -2), $submitted_values);
231
232     // Update items.
233     $field_state = static::getWidgetState($parents, $field_name, $form_state);
234     $field_state['items'] = $submitted_values;
235     static::setWidgetState($parents, $field_name, $form_state, $field_state);
236
237     $form_state->setRebuild();
238   }
239
240   /**
241    * Submission handler for the "Remove" button.
242    */
243   public static function removeSubmit(array $form, FormStateInterface $form_state) {
244     $button = $form_state->getTriggeringElement();
245
246     // Go one level up in the form, to the single field item element container.
247     $element = NestedArray::getValue($form, array_slice($button['#array_parents'], 0, -1));
248
249     $form_state->setValueForElement($element, ['target_id' => NULL, 'entity' => NULL]);
250
251     // Call the generic submit handler which takes care of removing the item.
252     static::addMoreSubmit($form, $form_state);
253   }
254
255   /**
256    * Sets the unique HTML ID of the widget's wrapping element.
257    *
258    * @param string $wrapperId
259    *   The unique HTML ID.
260    */
261   public function setWrapperId($wrapperId) {
262     if (!$this->wrapperId) {
263       $this->wrapperId = $wrapperId;
264     }
265   }
266
267   /**
268    * Gets the unique HTML ID of the widget's wrapping element.
269    *
270    * @return string
271    *   The unique HTML ID.
272    */
273   public function getWrapperId() {
274     return $this->wrapperId;
275   }
276
277 }