Added missing modules, including some as submodules.
[yaffs-website] / web / modules / contrib / paragraphs / src / Plugin / Field / FieldWidget / InlineParagraphsWidget.php
1 <?php
2
3 namespace Drupal\paragraphs\Plugin\Field\FieldWidget;
4
5 use Drupal\Component\Utility\NestedArray;
6 use Drupal\Component\Utility\Html;
7 use Drupal\Core\Entity\Entity\EntityFormDisplay;
8 use Drupal\Core\Entity\EntityInterface;
9 use Drupal\Core\Entity\RevisionableInterface;
10 use Drupal\Core\Field\FieldDefinitionInterface;
11 use Drupal\Core\Field\FieldFilteredMarkup;
12 use Drupal\Core\Field\FieldStorageDefinitionInterface;
13 use Drupal\Core\Field\WidgetBase;
14 use Drupal\Core\Form\FormStateInterface;
15 use Drupal\Core\Field\FieldItemListInterface;
16 use Drupal\Core\Render\Element;
17 use Drupal\node\Entity\Node;
18 use Drupal\paragraphs;
19 use Drupal\paragraphs\ParagraphInterface;
20 use Symfony\Component\Validator\ConstraintViolationInterface;
21
22
23 /**
24  * Plugin implementation of the 'entity_reference paragraphs' widget.
25  *
26  * We hide add / remove buttons when translating to avoid accidental loss of
27  * data because these actions effect all languages.
28  *
29  * @FieldWidget(
30  *   id = "entity_reference_paragraphs",
31  *   label = @Translation("Paragraphs Classic"),
32  *   description = @Translation("A paragraphs inline form widget."),
33  *   field_types = {
34  *     "entity_reference_revisions"
35  *   }
36  * )
37  */
38 class InlineParagraphsWidget extends WidgetBase {
39
40   /**
41    * Indicates whether the current widget instance is in translation.
42    *
43    * @var bool
44    */
45   private $isTranslating;
46
47   /**
48    * Id to name ajax buttons that includes field parents and field name.
49    *
50    * @var string
51    */
52   protected $fieldIdPrefix;
53
54   /**
55    * Wrapper id to identify the paragraphs.
56    *
57    * @var string
58    */
59   protected $fieldWrapperId;
60
61   /**
62    * Number of paragraphs item on form.
63    *
64    * @var int
65    */
66   protected $realItemCount;
67
68   /**
69    * Parents for the current paragraph.
70    *
71    * @var array
72    */
73   protected $fieldParents;
74
75   /**
76    * Accessible paragraphs types.
77    *
78    * @var array
79    */
80   protected $accessOptions = NULL;
81
82   /**
83    * {@inheritdoc}
84    */
85   public static function defaultSettings() {
86     return array(
87       'title' => t('Paragraph'),
88       'title_plural' => t('Paragraphs'),
89       'edit_mode' => 'open',
90       'add_mode' => 'dropdown',
91       'form_display_mode' => 'default',
92       'default_paragraph_type' => '',
93     );
94   }
95
96   /**
97    * {@inheritdoc}
98    */
99   public function settingsForm(array $form, FormStateInterface $form_state) {
100     $elements = array();
101
102     $elements['title'] = array(
103       '#type' => 'textfield',
104       '#title' => $this->t('Paragraph Title'),
105       '#description' => $this->t('Label to appear as title on the button as "Add new [title]", this label is translatable'),
106       '#default_value' => $this->getSetting('title'),
107       '#required' => TRUE,
108     );
109
110     $elements['title_plural'] = array(
111       '#type' => 'textfield',
112       '#title' => $this->t('Plural Paragraph Title'),
113       '#description' => $this->t('Title in its plural form.'),
114       '#default_value' => $this->getSetting('title_plural'),
115       '#required' => TRUE,
116     );
117
118     $elements['edit_mode'] = array(
119       '#type' => 'select',
120       '#title' => $this->t('Edit mode'),
121       '#description' => $this->t('The mode the paragraph is in by default. Preview will render the paragraph in the preview view mode.'),
122       '#options' => array(
123         'open' => $this->t('Open'),
124         'closed' => $this->t('Closed'),
125         'preview' => $this->t('Preview'),
126       ),
127       '#default_value' => $this->getSetting('edit_mode'),
128       '#required' => TRUE,
129     );
130
131     $elements['add_mode'] = array(
132       '#type' => 'select',
133       '#title' => $this->t('Add mode'),
134       '#description' => $this->t('The way to add new paragraphs.'),
135       '#options' => array(
136         'select' => $this->t('Select list'),
137         'button' => $this->t('Buttons'),
138         'dropdown' => $this->t('Dropdown button')
139       ),
140       '#default_value' => $this->getSetting('add_mode'),
141       '#required' => TRUE,
142     );
143
144     $elements['form_display_mode'] = array(
145       '#type' => 'select',
146       '#options' => \Drupal::service('entity_display.repository')->getFormModeOptions($this->getFieldSetting('target_type')),
147       '#description' => $this->t('The form display mode to use when rendering the paragraph form.'),
148       '#title' => $this->t('Form display mode'),
149       '#default_value' => $this->getSetting('form_display_mode'),
150       '#required' => TRUE,
151     );
152
153     $options  = [];
154     foreach ($this->getAllowedTypes() as $key => $bundle) {
155       $options[$key] = $bundle['label'];
156     }
157
158     $elements['default_paragraph_type'] = [
159       '#type' => 'select',
160       '#title' => $this->t('Default paragraph type'),
161       '#empty_value' => '_none',
162       '#default_value' => $this->getDefaultParagraphTypeMachineName(),
163       '#options' => $options,
164       '#description' => $this->t('When creating a new host entity, a paragraph of this type is added.'),
165     ];
166
167     return $elements;
168   }
169
170   /**
171    * {@inheritdoc}
172    */
173   public function settingsSummary() {
174     $summary = array();
175     $summary[] = $this->t('Title: @title', ['@title' => $this->getSetting('title')]);
176     $summary[] = $this->t('Plural title: @title_plural', [
177       '@title_plural' => $this->getSetting('title_plural')
178     ]);
179
180     switch($this->getSetting('edit_mode')) {
181       case 'open':
182       default:
183         $edit_mode = $this->t('Open');
184         break;
185       case 'closed':
186         $edit_mode = $this->t('Closed');
187         break;
188       case 'preview':
189         $edit_mode = $this->t('Preview');
190         break;
191     }
192
193     switch($this->getSetting('add_mode')) {
194       case 'select':
195       default:
196         $add_mode = $this->t('Select list');
197         break;
198       case 'button':
199         $add_mode = $this->t('Buttons');
200         break;
201       case 'dropdown':
202         $add_mode = $this->t('Dropdown button');
203         break;
204     }
205
206     $summary[] = $this->t('Edit mode: @edit_mode', ['@edit_mode' => $edit_mode]);
207     $summary[] = $this->t('Add mode: @add_mode', ['@add_mode' => $add_mode]);
208     $summary[] = $this->t('Form display mode: @form_display_mode', [
209       '@form_display_mode' => $this->getSetting('form_display_mode')
210     ]);
211     if ($this->getDefaultParagraphTypeLabelName() !== NULL) {
212       $summary[] = $this->t('Default paragraph type: @default_paragraph_type', [
213         '@default_paragraph_type' => $this->getDefaultParagraphTypeLabelName()
214       ]);
215     }
216
217     return $summary;
218   }
219
220   /**
221    * {@inheritdoc}
222    *
223    * @see \Drupal\content_translation\Controller\ContentTranslationController::prepareTranslation()
224    *   Uses a similar approach to populate a new translation.
225    */
226   public function formElement(FieldItemListInterface $items, $delta, array $element, array &$form, FormStateInterface $form_state) {
227     $field_name = $this->fieldDefinition->getName();
228     $parents = $element['#field_parents'];
229     $info = [];
230
231     $paragraphs_entity = NULL;
232     $host = $items->getEntity();
233     $widget_state = static::getWidgetState($parents, $field_name, $form_state);
234
235     $entity_manager = \Drupal::entityTypeManager();
236     $target_type = $this->getFieldSetting('target_type');
237
238     $item_mode = isset($widget_state['paragraphs'][$delta]['mode']) ? $widget_state['paragraphs'][$delta]['mode'] : 'edit';
239     $default_edit_mode = $this->getSetting('edit_mode');
240
241     $show_must_be_saved_warning = !empty($widget_state['paragraphs'][$delta]['show_warning']);
242
243     if (isset($widget_state['paragraphs'][$delta]['entity'])) {
244       $paragraphs_entity = $widget_state['paragraphs'][$delta]['entity'];
245     }
246     elseif (isset($items[$delta]->entity)) {
247       $paragraphs_entity = $items[$delta]->entity;
248
249       // We don't have a widget state yet, get from selector settings.
250       if (!isset($widget_state['paragraphs'][$delta]['mode'])) {
251
252         if ($default_edit_mode == 'open') {
253           $item_mode = 'edit';
254         }
255         elseif ($default_edit_mode == 'closed') {
256           $item_mode = 'closed';
257         }
258         elseif ($default_edit_mode == 'preview') {
259           $item_mode = 'preview';
260         }
261       }
262     }
263     elseif (isset($widget_state['selected_bundle'])) {
264
265       $entity_type = $entity_manager->getDefinition($target_type);
266       $bundle_key = $entity_type->getKey('bundle');
267
268       $paragraphs_entity = $entity_manager->getStorage($target_type)->create(array(
269         $bundle_key => $widget_state['selected_bundle'],
270       ));
271
272       $item_mode = 'edit';
273     }
274
275     if ($item_mode == 'collapsed') {
276       $item_mode = $default_edit_mode;
277     }
278
279     if ($item_mode == 'closed') {
280       // Validate closed paragraphs and expand if needed.
281       // @todo Consider recursion.
282       $violations = $paragraphs_entity->validate();
283       $violations->filterByFieldAccess();
284       if (count($violations) > 0) {
285         $item_mode = 'edit';
286         $messages = [];
287         foreach ($violations as $violation) {
288           $messages[] = $violation->getMessage();
289         }
290         $info['validation_error'] = array(
291           '#type' => 'container',
292           '#markup' => $this->t('@messages', ['@messages' => strip_tags(implode('\n', $messages))]),
293           '#attributes' => ['class' => ['messages', 'messages--warning']],
294         );
295       }
296     }
297
298     if ($paragraphs_entity) {
299       // Detect if we are translating.
300       $this->initIsTranslating($form_state, $host);
301       $langcode = $form_state->get('langcode');
302
303       if (!$this->isTranslating) {
304         // Set the langcode if we are not translating.
305         $langcode_key = $paragraphs_entity->getEntityType()->getKey('langcode');
306         if ($paragraphs_entity->get($langcode_key)->value != $langcode) {
307           // If a translation in the given language already exists, switch to
308           // that. If there is none yet, update the language.
309           if ($paragraphs_entity->hasTranslation($langcode)) {
310             $paragraphs_entity = $paragraphs_entity->getTranslation($langcode);
311           }
312           else {
313             $paragraphs_entity->set($langcode_key, $langcode);
314           }
315         }
316       }
317       else {
318         // Add translation if missing for the target language.
319         if (!$paragraphs_entity->hasTranslation($langcode)) {
320           // Get the selected translation of the paragraph entity.
321           $entity_langcode = $paragraphs_entity->language()->getId();
322           $source = $form_state->get(['content_translation', 'source']);
323           $source_langcode = $source ? $source->getId() : $entity_langcode;
324           $paragraphs_entity = $paragraphs_entity->getTranslation($source_langcode);
325           // The paragraphs entity has no content translation source field if
326           // no paragraph entity field is translatable, even if the host is.
327           if ($paragraphs_entity->hasField('content_translation_source')) {
328             // Initialise the translation with source language values.
329             $paragraphs_entity->addTranslation($langcode, $paragraphs_entity->toArray());
330             $translation = $paragraphs_entity->getTranslation($langcode);
331             $manager = \Drupal::service('content_translation.manager');
332             $manager->getTranslationMetadata($translation)->setSource($paragraphs_entity->language()->getId());
333           }
334         }
335         // If any paragraphs type is translatable do not switch.
336         if ($paragraphs_entity->hasField('content_translation_source')) {
337           // Switch the paragraph to the translation.
338           $paragraphs_entity = $paragraphs_entity->getTranslation($langcode);
339         }
340       }
341
342       $element_parents = $parents;
343       $element_parents[] = $field_name;
344       $element_parents[] = $delta;
345       $element_parents[] = 'subform';
346
347       $id_prefix = implode('-', array_merge($parents, array($field_name, $delta)));
348       $wrapper_id = Html::getUniqueId($id_prefix . '-item-wrapper');
349
350       $element += array(
351         '#type' => 'container',
352         '#element_validate' => array(array($this, 'elementValidate')),
353         'subform' => array(
354           '#type' => 'container',
355           '#parents' => $element_parents,
356         ),
357       );
358
359       $element['#prefix'] = '<div id="' . $wrapper_id . '">';
360       $element['#suffix'] = '</div>';
361
362       $item_bundles = \Drupal::service('entity_type.bundle.info')->getBundleInfo($target_type);
363       if (isset($item_bundles[$paragraphs_entity->bundle()])) {
364         $bundle_info = $item_bundles[$paragraphs_entity->bundle()];
365
366         $element['top'] = array(
367           '#type' => 'container',
368           '#weight' => -1000,
369           '#attributes' => array(
370             'class' => array(
371               'paragraph-type-top',
372             ),
373           ),
374         );
375
376         $element['top']['paragraph_type_title'] = array(
377           '#type' => 'container',
378           '#weight' => 0,
379           '#attributes' => array(
380             'class' => array(
381               'paragraph-type-title',
382             ),
383           ),
384         );
385
386         $element['top']['paragraph_type_title']['info'] = array(
387           '#markup' => $bundle_info['label'],
388         );
389
390         $actions = array();
391         $links = array();
392
393         // Hide the button when translating.
394         $button_access = $paragraphs_entity->access('delete') && !$this->isTranslating;
395         if ($item_mode != 'remove') {
396           $links['remove_button'] = [
397             '#type' => 'submit',
398             '#value' => $this->t('Remove'),
399             '#name' => strtr($id_prefix, '-', '_') . '_remove',
400             '#weight' => 501,
401             '#submit' => [[get_class($this), 'paragraphsItemSubmit']],
402             '#limit_validation_errors' => [array_merge($parents, [$field_name, 'add_more'])],
403             '#delta' => $delta,
404             '#ajax' => [
405               'callback' => [get_class($this), 'itemAjax'],
406               'wrapper' => $widget_state['ajax_wrapper_id'],
407               'effect' => 'fade',
408             ],
409             '#access' => $button_access,
410             '#prefix' => '<li class="remove">',
411             '#suffix' => '</li>',
412             '#paragraphs_mode' => 'remove',
413           ];
414
415         }
416
417         if ($item_mode == 'edit') {
418
419           if (isset($items[$delta]->entity) && ($default_edit_mode == 'preview' || $default_edit_mode == 'closed')) {
420             $links['collapse_button'] = array(
421               '#type' => 'submit',
422               '#value' => $this->t('Collapse'),
423               '#name' => strtr($id_prefix, '-', '_') . '_collapse',
424               '#weight' => 499,
425               '#submit' => array(array(get_class($this), 'paragraphsItemSubmit')),
426               '#delta' => $delta,
427               '#ajax' => array(
428                 'callback' => array(get_class($this), 'itemAjax'),
429                 'wrapper' => $widget_state['ajax_wrapper_id'],
430                 'effect' => 'fade',
431               ),
432               '#access' => $paragraphs_entity->access('update'),
433               '#prefix' => '<li class="collapse">',
434               '#suffix' => '</li>',
435               '#paragraphs_mode' => 'collapsed',
436               '#paragraphs_show_warning' => TRUE,
437             );
438           }
439
440           // Hide the button when translating.
441           $button_access = $paragraphs_entity->access('delete') && !$this->isTranslating;
442
443           $info['edit_button_info'] = array(
444             '#type' => 'container',
445             '#markup' => $this->t('You are not allowed to edit this @title.', array('@title' => $this->getSetting('title'))),
446             '#attributes' => ['class' => ['messages', 'messages--warning']],
447             '#access' => !$paragraphs_entity->access('update') && $paragraphs_entity->access('delete'),
448           );
449
450           $info['remove_button_info'] = array(
451             '#type' => 'container',
452             '#markup' => $this->t('You are not allowed to remove this @title.', array('@title' => $this->getSetting('title'))),
453             '#attributes' => ['class' => ['messages', 'messages--warning']],
454             '#access' => !$paragraphs_entity->access('delete') && $paragraphs_entity->access('update'),
455           );
456
457           $info['edit_remove_button_info'] = array(
458             '#type' => 'container',
459             '#markup' => $this->t('You are not allowed to edit or remove this @title.', array('@title' => $this->getSetting('title'))),
460             '#attributes' => ['class' => ['messages', 'messages--warning']],
461             '#access' => !$paragraphs_entity->access('update') && !$paragraphs_entity->access('delete'),
462           );
463         }
464         elseif ($item_mode == 'preview' || $item_mode == 'closed') {
465           $links['edit_button'] = array(
466             '#type' => 'submit',
467             '#value' => $this->t('Edit'),
468             '#name' => strtr($id_prefix, '-', '_') . '_edit',
469             '#weight' => 500,
470             '#submit' => array(array(get_class($this), 'paragraphsItemSubmit')),
471             '#limit_validation_errors' => array(array_merge($parents, array($field_name, 'add_more'))),
472             '#delta' => $delta,
473             '#ajax' => array(
474               'callback' => array(get_class($this), 'itemAjax'),
475               'wrapper' => $widget_state['ajax_wrapper_id'],
476               'effect' => 'fade',
477             ),
478             '#access' => $paragraphs_entity->access('update'),
479             '#prefix' => '<li class="edit">',
480             '#suffix' => '</li>',
481             '#paragraphs_mode' => 'edit',
482           );
483
484           if ($show_must_be_saved_warning) {
485             $info['must_be_saved_info'] = array(
486               '#type' => 'container',
487               '#markup' => $this->t('You have unsaved changes on this @title item.', array('@title' => $this->getSetting('title'))),
488               '#attributes' => ['class' => ['messages', 'messages--warning']],
489             );
490           }
491
492           $info['preview_info'] = array(
493             '#type' => 'container',
494             '#markup' => $this->t('You are not allowed to view this @title.', array('@title' => $this->getSetting('title'))),
495             '#attributes' => ['class' => ['messages', 'messages--warning']],
496             '#access' => !$paragraphs_entity->access('view'),
497           );
498
499           $info['edit_button_info'] = array(
500             '#type' => 'container',
501             '#markup' => $this->t('You are not allowed to edit this @title.', array('@title' => $this->getSetting('title'))),
502             '#attributes' => ['class' => ['messages', 'messages--warning']],
503             '#access' => !$paragraphs_entity->access('update') && $paragraphs_entity->access('delete'),
504           );
505
506           $info['remove_button_info'] = array(
507             '#type' => 'container',
508             '#markup' => $this->t('You are not allowed to remove this @title.', array('@title' => $this->getSetting('title'))),
509             '#attributes' => ['class' => ['messages', 'messages--warning']],
510             '#access' => !$paragraphs_entity->access('delete') && $paragraphs_entity->access('update'),
511           );
512
513           $info['edit_remove_button_info'] = array(
514             '#type' => 'container',
515             '#markup' => $this->t('You are not allowed to edit or remove this @title.', array('@title' => $this->getSetting('title'))),
516             '#attributes' => ['class' => ['messages', 'messages--warning']],
517             '#access' => !$paragraphs_entity->access('update') && !$paragraphs_entity->access('delete'),
518           );
519         }
520         elseif ($item_mode == 'remove') {
521
522           $element['top']['paragraph_type_title']['info'] = [
523             '#markup' => $this->t('Deleted @title: %type', ['@title' => $this->getSetting('title'), '%type' => $bundle_info['label']]),
524           ];
525
526           $links['confirm_remove_button'] = [
527             '#type' => 'submit',
528             '#value' => $this->t('Confirm removal'),
529             '#name' => strtr($id_prefix, '-', '_') . '_confirm_remove',
530             '#weight' => 503,
531             '#submit' => [[get_class($this), 'paragraphsItemSubmit']],
532             '#limit_validation_errors' => [array_merge($parents, [$field_name, 'add_more'])],
533             '#delta' => $delta,
534             '#ajax' => [
535               'callback' => [get_class($this), 'itemAjax'],
536               'wrapper' => $widget_state['ajax_wrapper_id'],
537               'effect' => 'fade',
538             ],
539             '#prefix' => '<li class="confirm-remove">',
540             '#suffix' => '</li>',
541             '#paragraphs_mode' => 'removed',
542           ];
543
544           $links['restore_button'] = [
545             '#type' => 'submit',
546             '#value' => $this->t('Restore'),
547             '#name' => strtr($id_prefix, '-', '_') . '_restore',
548             '#weight' => 504,
549             '#submit' => [[get_class($this), 'paragraphsItemSubmit']],
550             '#limit_validation_errors' => [array_merge($parents, [$field_name, 'add_more'])],
551             '#delta' => $delta,
552             '#ajax' => [
553               'callback' => [get_class($this), 'itemAjax'],
554               'wrapper' => $widget_state['ajax_wrapper_id'],
555               'effect' => 'fade',
556             ],
557             '#prefix' => '<li class="restore">',
558             '#suffix' => '</li>',
559             '#paragraphs_mode' => 'edit',
560           ];
561         }
562
563         if (count($links)) {
564           $show_links = 0;
565           foreach($links as $link_item) {
566             if (!isset($link_item['#access']) || $link_item['#access']) {
567               $show_links++;
568             }
569           }
570
571           if ($show_links > 0) {
572
573             $element['top']['links'] = $links;
574             if ($show_links > 1) {
575               $element['top']['links']['#theme_wrappers'] = array('dropbutton_wrapper', 'paragraphs_dropbutton_wrapper');
576               $element['top']['links']['prefix'] = array(
577                 '#markup' => '<ul class="dropbutton">',
578                 '#weight' => -999,
579               );
580               $element['top']['links']['suffix'] = array(
581                 '#markup' => '</li>',
582                 '#weight' => 999,
583               );
584             }
585             else {
586               $element['top']['links']['#theme_wrappers'] = array('paragraphs_dropbutton_wrapper');
587               foreach($links as $key => $link_item) {
588                 unset($element['top']['links'][$key]['#prefix']);
589                 unset($element['top']['links'][$key]['#suffix']);
590               }
591             }
592             $element['top']['links']['#weight'] = 2;
593           }
594         }
595
596         if (count($info)) {
597           $show_info = FALSE;
598           foreach($info as $info_item) {
599             if (!isset($info_item['#access']) || $info_item['#access']) {
600               $show_info = TRUE;
601               break;
602             }
603           }
604
605           if ($show_info) {
606             $element['info'] = $info;
607             $element['info']['#weight'] = 998;
608           }
609         }
610
611         if (count($actions)) {
612           $show_actions = FALSE;
613           foreach($actions as $action_item) {
614             if (!isset($action_item['#access']) || $action_item['#access']) {
615               $show_actions = TRUE;
616               break;
617             }
618           }
619
620           if ($show_actions) {
621             $element['actions'] = $actions;
622             $element['actions']['#type'] = 'actions';
623             $element['actions']['#weight'] = 999;
624           }
625         }
626       }
627
628       $display = EntityFormDisplay::collectRenderDisplay($paragraphs_entity, $this->getSetting('form_display_mode'));
629
630       // @todo Remove as part of https://www.drupal.org/node/2640056
631       if (\Drupal::moduleHandler()->moduleExists('field_group')) {
632         $context = [
633           'entity_type' => $paragraphs_entity->getEntityTypeId(),
634           'bundle' => $paragraphs_entity->bundle(),
635           'entity' => $paragraphs_entity,
636           'context' => 'form',
637           'display_context' => 'form',
638           'mode' => $display->getMode(),
639         ];
640
641         field_group_attach_groups($element['subform'], $context);
642         $element['subform']['#pre_render'][] = 'field_group_form_pre_render';
643       }
644
645       if ($item_mode == 'edit') {
646         $display->buildForm($paragraphs_entity, $element['subform'], $form_state);
647         foreach (Element::children($element['subform']) as $field) {
648           if ($paragraphs_entity->hasField($field)) {
649             $translatable = $paragraphs_entity->{$field}->getFieldDefinition()->isTranslatable();
650             if ($translatable) {
651               $element['subform'][$field]['widget']['#after_build'][] = [
652                 static::class,
653                 'removeTranslatabilityClue'
654               ];
655             }
656           }
657         }
658       }
659       elseif ($item_mode == 'preview') {
660         $element['subform'] = array();
661         $element['behavior_plugins'] = [];
662         $element['preview'] = entity_view($paragraphs_entity, 'preview', $paragraphs_entity->language()->getId());
663         $element['preview']['#access'] = $paragraphs_entity->access('view');
664       }
665       elseif ($item_mode == 'closed') {
666         $element['subform'] = array();
667         $element['behavior_plugins'] = [];
668         if ($paragraphs_entity) {
669           $summary = $this->addCollapsedSummary($paragraphs_entity);
670           $element['top']['paragraph_summary']['fields_info'] = [
671             '#markup' => $summary,
672             '#prefix' => '<div class="paragraphs-collapsed-description">',
673             '#suffix' => '</div>',
674           ];
675         }
676       }
677       else {
678         $element['subform'] = array();
679       }
680
681       $element['subform']['#attributes']['class'][] = 'paragraphs-subform';
682       $element['subform']['#access'] = $paragraphs_entity->access('update');
683
684       if ($item_mode == 'removed') {
685         $element['#access'] = FALSE;
686       }
687
688       $widget_state['paragraphs'][$delta]['entity'] = $paragraphs_entity;
689       $widget_state['paragraphs'][$delta]['display'] = $display;
690       $widget_state['paragraphs'][$delta]['mode'] = $item_mode;
691
692       static::setWidgetState($parents, $field_name, $form_state, $widget_state);
693     }
694     else {
695       $element['#access'] = FALSE;
696     }
697
698     return $element;
699   }
700
701   public function getAllowedTypes() {
702
703     $return_bundles = array();
704
705     $target_type = $this->getFieldSetting('target_type');
706     $bundles = \Drupal::service('entity_type.bundle.info')->getBundleInfo($target_type);
707
708     if ($this->getSelectionHandlerSetting('target_bundles') !== NULL) {
709       $bundles = array_intersect_key($bundles, $this->getSelectionHandlerSetting('target_bundles'));
710     }
711
712     // Support for the paragraphs reference type.
713     $drag_drop_settings = $this->getSelectionHandlerSetting('target_bundles_drag_drop');
714     if ($drag_drop_settings) {
715       $max_weight = count($bundles);
716
717       foreach ($drag_drop_settings as $bundle_info) {
718         if (isset($bundle_info['weight']) && $bundle_info['weight'] && $bundle_info['weight'] > $max_weight) {
719           $max_weight = $bundle_info['weight'];
720         }
721       }
722
723       // Default weight for new items.
724       $weight = $max_weight + 1;
725       foreach ($bundles as $machine_name => $bundle) {
726         $return_bundles[$machine_name] = array(
727           'label' => $bundle['label'],
728           'weight' => isset($drag_drop_settings[$machine_name]['weight']) ? $drag_drop_settings[$machine_name]['weight'] : $weight,
729         );
730         $weight++;
731       }
732     }
733     // Support for other reference types.
734     else {
735       $weight = 0;
736       foreach ($bundles as $machine_name => $bundle) {
737         if (!count($this->getSelectionHandlerSetting('target_bundles'))
738           || in_array($machine_name, $this->getSelectionHandlerSetting('target_bundles'))) {
739
740           $return_bundles[$machine_name] = array(
741             'label' => $bundle['label'],
742             'weight' => $weight,
743           );
744
745           $weight++;
746         }
747       }
748     }
749
750     uasort($return_bundles, 'Drupal\Component\Utility\SortArray::sortByWeightElement');
751
752     return $return_bundles;
753   }
754
755   public function formMultipleElements(FieldItemListInterface $items, array &$form, FormStateInterface $form_state) {
756     $field_name = $this->fieldDefinition->getName();
757     $cardinality = $this->fieldDefinition->getFieldStorageDefinition()->getCardinality();
758     $this->fieldParents = $form['#parents'];
759     $field_state = static::getWidgetState($this->fieldParents, $field_name, $form_state);
760
761     $max = $field_state['items_count'];
762     $entity_type_manager = \Drupal::entityTypeManager();
763
764     // Consider adding a default paragraph for new host entities.
765     if ($max == 0 && $items->getEntity()->isNew()) {
766       $default_type = $this->getDefaultParagraphTypeMachineName();
767
768       // Checking if default_type is not none and if is allowed.
769       if ($default_type) {
770         // Place the default paragraph.
771         $target_type = $this->getFieldSetting('target_type');
772         $paragraphs_entity = $entity_type_manager->getStorage($target_type)->create([
773           'type' => $default_type,
774         ]);
775         $field_state['selected_bundle'] = $default_type;
776         $display = EntityFormDisplay::collectRenderDisplay($paragraphs_entity, $this->getSetting('form_display_mode'));
777         $field_state['paragraphs'][0] = [
778           'entity' => $paragraphs_entity,
779           'display' => $display,
780           'mode' => 'edit',
781           'original_delta' => 1
782         ];
783         $max = 1;
784         $field_state['items_count'] = $max;
785       }
786     }
787
788     $this->realItemCount = $max;
789     $is_multiple = $this->fieldDefinition->getFieldStorageDefinition()->isMultiple();
790
791     $title = $this->fieldDefinition->getLabel();
792     $description = FieldFilteredMarkup::create(\Drupal::token()->replace($this->fieldDefinition->getDescription()));
793
794     $elements = array();
795     $this->fieldIdPrefix = implode('-', array_merge($this->fieldParents, array($field_name)));
796     $this->fieldWrapperId = Html::getUniqueId($this->fieldIdPrefix . '-add-more-wrapper');
797     $elements['#prefix'] = '<div id="' . $this->fieldWrapperId . '">';
798     $elements['#suffix'] = '</div>';
799
800     $field_state['ajax_wrapper_id'] = $this->fieldWrapperId;
801     // Persist the widget state so formElement() can access it.
802     static::setWidgetState($this->fieldParents, $field_name, $form_state, $field_state);
803
804     if ($max > 0) {
805       for ($delta = 0; $delta < $max; $delta++) {
806
807         // Add a new empty item if it doesn't exist yet at this delta.
808         if (!isset($items[$delta])) {
809           $items->appendItem();
810         }
811
812         // For multiple fields, title and description are handled by the wrapping
813         // table.
814         $element = array(
815           '#title' => $is_multiple ? '' : $title,
816           '#description' => $is_multiple ? '' : $description,
817         );
818         $element = $this->formSingleElement($items, $delta, $element, $form, $form_state);
819
820         if ($element) {
821           // Input field for the delta (drag-n-drop reordering).
822           if ($is_multiple) {
823             // We name the element '_weight' to avoid clashing with elements
824             // defined by widget.
825             $element['_weight'] = array(
826               '#type' => 'weight',
827               '#title' => $this->t('Weight for row @number', array('@number' => $delta + 1)),
828               '#title_display' => 'invisible',
829               // Note: this 'delta' is the FAPI #type 'weight' element's property.
830               '#delta' => $max,
831               '#default_value' => $items[$delta]->_weight ?: $delta,
832               '#weight' => 100,
833             );
834           }
835
836           // Access for the top element is set to FALSE only when the paragraph
837           // was removed. A paragraphs that a user can not edit has access on
838           // lower level.
839           if (isset($element['#access']) && !$element['#access']) {
840             $this->realItemCount--;
841           }
842           else {
843             $elements[$delta] = $element;
844           }
845         }
846       }
847     }
848
849     $field_state = static::getWidgetState($this->fieldParents, $field_name, $form_state);
850     $field_state['real_item_count'] = $this->realItemCount;
851     static::setWidgetState($this->fieldParents, $field_name, $form_state, $field_state);
852
853     if ($this->realItemCount > 0) {
854       $elements += array(
855         '#theme' => 'field_multiple_value_form',
856         '#field_name' => $field_name,
857         '#cardinality' => $cardinality,
858         '#cardinality_multiple' => $is_multiple,
859         '#required' => $this->fieldDefinition->isRequired(),
860         '#title' => $title,
861         '#description' => $description,
862         '#max_delta' => $max-1,
863       );
864     }
865     else {
866       $elements += [
867         '#type' => 'container',
868         '#theme_wrappers' => ['container'],
869         '#field_name' => $field_name,
870         '#cardinality' => $cardinality,
871         '#cardinality_multiple' => TRUE,
872         '#max_delta' => $max-1,
873         'title' => [
874           '#type' => 'html_tag',
875           '#tag' => 'strong',
876           '#value' => $title,
877         ],
878         'text' => [
879           '#type' => 'container',
880           'value' => [
881             '#markup' => $this->t('No @title added yet.', ['@title' => $this->getSetting('title')]),
882             '#prefix' => '<em>',
883             '#suffix' => '</em>',
884           ]
885         ],
886       ];
887
888       if ($description) {
889         $elements['description'] = [
890           '#type' => 'container',
891           'value' => ['#markup' => $description],
892           '#attributes' => ['class' => ['description']],
893         ];
894       }
895     }
896
897     $host = $items->getEntity();
898     $this->initIsTranslating($form_state, $host);
899
900     if (($this->realItemCount < $cardinality || $cardinality == FieldStorageDefinitionInterface::CARDINALITY_UNLIMITED) && !$form_state->isProgrammed() && !$this->isTranslating) {
901       $elements['add_more'] = $this->buildAddActions();
902     }
903
904     $elements['#attached']['library'][] = 'paragraphs/drupal.paragraphs.admin';
905
906     return $elements;
907   }
908
909   /**
910    * {@inheritdoc}
911    */
912   public function form(FieldItemListInterface $items, array &$form, FormStateInterface $form_state, $get_delta = NULL) {
913     $parents = $form['#parents'];
914
915     // Identify the manage field settings default value form.
916     if (in_array('default_value_input', $parents, TRUE)) {
917       // Since the entity is not reusable neither cloneable, having a default
918       // value is not supported.
919       return ['#markup' => $this->t('No widget available for: %label.', ['%label' => $items->getFieldDefinition()->getLabel()])];
920     }
921
922     return parent::form($items, $form, $form_state, $get_delta);
923   }
924
925   /**
926    * Add 'add more' button, if not working with a programmed form.
927    *
928    * @return array
929    *    The form element array.
930    */
931   protected function buildAddActions() {
932     if (count($this->getAccessibleOptions()) === 0) {
933       if (count($this->getAllowedTypes()) === 0) {
934         $add_more_elements['info'] = [
935           '#type' => 'container',
936           '#markup' => $this->t('You are not allowed to add any of the @title types.', ['@title' => $this->getSetting('title')]),
937           '#attributes' => ['class' => ['messages', 'messages--warning']],
938         ];
939       }
940       else {
941         $add_more_elements['info'] = [
942           '#type' => 'container',
943           '#markup' => $this->t('You did not add any @title types yet.', ['@title' => $this->getSetting('title')]),
944           '#attributes' => ['class' => ['messages', 'messages--warning']],
945         ];
946       }
947
948       return $add_more_elements ;
949     }
950
951     if ($this->getSetting('add_mode') == 'button' || $this->getSetting('add_mode') == 'dropdown') {
952       return $this->buildButtonsAddMode();
953     }
954
955     return $this->buildSelectAddMode();
956   }
957
958   /**
959    * Returns the available paragraphs type.
960    *
961    * @return array
962    *   Available paragraphs types.
963    */
964   protected function getAccessibleOptions() {
965     if ($this->accessOptions !== NULL) {
966       return $this->accessOptions;
967     }
968
969     $entity_type_manager = \Drupal::entityTypeManager();
970     $target_type = $this->getFieldSetting('target_type');
971     $bundles = $this->getAllowedTypes();
972     $access_control_handler = $entity_type_manager->getAccessControlHandler($target_type);
973     $dragdrop_settings = $this->getSelectionHandlerSetting('target_bundles_drag_drop');
974
975     foreach ($bundles as $machine_name => $bundle) {
976       if ($dragdrop_settings || (!count($this->getSelectionHandlerSetting('target_bundles'))
977           || in_array($machine_name, $this->getSelectionHandlerSetting('target_bundles')))) {
978         if ($access_control_handler->createAccess($machine_name)) {
979           $this->accessOptions[$machine_name] = $bundle['label'];
980         }
981       }
982     }
983
984     return $this->accessOptions;
985   }
986
987   /**
988    * Builds dropdown button for adding new paragraph.
989    *
990    * @return array
991    *   The form element array.
992    */
993   protected function buildButtonsAddMode() {
994     // Hide the button when translating.
995     $add_more_elements = [
996       '#type' => 'container',
997       '#theme_wrappers' => ['paragraphs_dropbutton_wrapper'],
998     ];
999     $field_name = $this->fieldDefinition->getName();
1000     $title = $this->fieldDefinition->getLabel();
1001
1002     $drop_button = FALSE;
1003     if (count($this->getAccessibleOptions()) > 1 && $this->getSetting('add_mode') == 'dropdown') {
1004       $drop_button = TRUE;
1005       $add_more_elements['#theme_wrappers'] = ['dropbutton_wrapper'];
1006       $add_more_elements['prefix'] = [
1007         '#markup' => '<ul class="dropbutton">',
1008         '#weight' => -999,
1009       ];
1010       $add_more_elements['suffix'] = [
1011         '#markup' => '</ul>',
1012         '#weight' => 999,
1013       ];
1014       $add_more_elements['#suffix'] = $this->t(' to %type', ['%type' => $title]);
1015     }
1016
1017     foreach ($this->getAccessibleOptions() as $machine_name => $label) {
1018       $add_more_elements['add_more_button_' . $machine_name] = [
1019         '#type' => 'submit',
1020         '#name' => strtr($this->fieldIdPrefix, '-', '_') . '_' . $machine_name . '_add_more',
1021         '#value' => $this->t('Add @type', ['@type' => $label]),
1022         '#attributes' => ['class' => ['field-add-more-submit']],
1023         '#limit_validation_errors' => [array_merge($this->fieldParents, [$field_name, 'add_more'])],
1024         '#submit' => [[get_class($this), 'addMoreSubmit']],
1025         '#ajax' => [
1026           'callback' => [get_class($this), 'addMoreAjax'],
1027           'wrapper' => $this->fieldWrapperId,
1028           'effect' => 'fade',
1029         ],
1030         '#bundle_machine_name' => $machine_name,
1031       ];
1032
1033       if ($drop_button) {
1034         $add_more_elements['add_more_button_' . $machine_name]['#prefix'] = '<li>';
1035         $add_more_elements['add_more_button_' . $machine_name]['#suffix'] = '</li>';
1036       }
1037     }
1038
1039     return $add_more_elements;
1040   }
1041
1042   /**
1043    * Builds list of actions based on paragraphs type.
1044    *
1045    * @return array
1046    *   The form element array.
1047    */
1048   protected function buildSelectAddMode() {
1049     $field_name = $this->fieldDefinition->getName();
1050     $title = $this->fieldDefinition->getLabel();
1051     $add_more_elements['add_more_select'] = [
1052       '#type' => 'select',
1053       '#options' => $this->getAccessibleOptions(),
1054       '#title' => $this->t('@title type', ['@title' => $this->getSetting('title')]),
1055       '#label_display' => 'hidden',
1056     ];
1057
1058     $text = $this->t('Add @title', ['@title' => $this->getSetting('title')]);
1059
1060     if ($this->realItemCount > 0) {
1061       $text = $this->t('Add another @title', ['@title' => $this->getSetting('title')]);
1062     }
1063
1064     $add_more_elements['add_more_button'] = [
1065       '#type' => 'submit',
1066       '#name' => strtr($this->fieldIdPrefix, '-', '_') . '_add_more',
1067       '#value' => $text,
1068       '#attributes' => ['class' => ['field-add-more-submit']],
1069       '#limit_validation_errors' => [array_merge($this->fieldParents, [$field_name, 'add_more'])],
1070       '#submit' => [[get_class($this), 'addMoreSubmit']],
1071       '#ajax' => [
1072         'callback' => [get_class($this), 'addMoreAjax'],
1073         'wrapper' => $this->fieldWrapperId,
1074         'effect' => 'fade',
1075       ],
1076     ];
1077
1078     $add_more_elements['add_more_button']['#suffix'] = $this->t(' to %type', ['%type' => $title]);
1079     return $add_more_elements;
1080   }
1081
1082   /**
1083    * Gets current language code from the form state or item.
1084    *
1085    * Since the paragraph field is not set as translatable, the item language
1086    * code is set to the source language. The intended translation language
1087    * is only accessibly through the form state.
1088    *
1089    * @param \Drupal\Core\Form\FormStateInterface $form_state
1090    * @param \Drupal\Core\Field\FieldItemListInterface $items
1091    * @return string
1092    */
1093   protected function getCurrentLangcode(FormStateInterface $form_state, FieldItemListInterface $items) {
1094     return $form_state->get('langcode') ?: $items->getEntity()->language()->getId();
1095   }
1096
1097   /**
1098    * {@inheritdoc}
1099    */
1100   public static function addMoreAjax(array $form, FormStateInterface $form_state) {
1101     $button = $form_state->getTriggeringElement();
1102     // Go one level up in the form, to the widgets container.
1103     $element = NestedArray::getValue($form, array_slice($button['#array_parents'], 0, -2));
1104
1105     // Add a DIV around the delta receiving the Ajax effect.
1106     $delta = $element['#max_delta'];
1107     $element[$delta]['#prefix'] = '<div class="ajax-new-content">' . (isset($element[$delta]['#prefix']) ? $element[$delta]['#prefix'] : '');
1108     $element[$delta]['#suffix'] = (isset($element[$delta]['#suffix']) ? $element[$delta]['#suffix'] : '') . '</div>';
1109
1110     return $element;
1111   }
1112
1113   /**
1114    * {@inheritdoc}
1115    */
1116   public static function addMoreSubmit(array $form, FormStateInterface $form_state) {
1117     $button = $form_state->getTriggeringElement();
1118
1119     // Go one level up in the form, to the widgets container.
1120     $element = NestedArray::getValue($form, array_slice($button['#array_parents'], 0, -2));
1121     $field_name = $element['#field_name'];
1122     $parents = $element['#field_parents'];
1123
1124     // Increment the items count.
1125     $widget_state = static::getWidgetState($parents, $field_name, $form_state);
1126
1127     if ($widget_state['real_item_count'] < $element['#cardinality'] || $element['#cardinality'] == FieldStorageDefinitionInterface::CARDINALITY_UNLIMITED) {
1128       $widget_state['items_count']++;
1129     }
1130
1131     if (isset($button['#bundle_machine_name'])) {
1132       $widget_state['selected_bundle'] = $button['#bundle_machine_name'];
1133     }
1134     else {
1135       $widget_state['selected_bundle'] = $element['add_more']['add_more_select']['#value'];
1136     }
1137
1138     static::setWidgetState($parents, $field_name, $form_state, $widget_state);
1139
1140     $form_state->setRebuild();
1141   }
1142
1143   public static function paragraphsItemSubmit(array $form, FormStateInterface $form_state) {
1144     $button = $form_state->getTriggeringElement();
1145
1146     // Go one level up in the form, to the widgets container.
1147     $element = NestedArray::getValue($form, array_slice($button['#array_parents'], 0, -4));
1148
1149     $delta = array_slice($button['#array_parents'], -4, -3);
1150     $delta = $delta[0];
1151
1152     $field_name = $element['#field_name'];
1153     $parents = $element['#field_parents'];
1154
1155     $widget_state = static::getWidgetState($parents, $field_name, $form_state);
1156
1157     $widget_state['paragraphs'][$delta]['mode'] = $button['#paragraphs_mode'];
1158
1159     if (!empty($button['#paragraphs_show_warning'])) {
1160       $widget_state['paragraphs'][$delta]['show_warning'] = $button['#paragraphs_show_warning'];
1161     }
1162
1163     static::setWidgetState($parents, $field_name, $form_state, $widget_state);
1164
1165     $form_state->setRebuild();
1166   }
1167
1168   public static function itemAjax(array $form, FormStateInterface $form_state) {
1169     $button = $form_state->getTriggeringElement();
1170     // Go one level up in the form, to the widgets container.
1171     $element = NestedArray::getValue($form, array_slice($button['#array_parents'], 0, -4));
1172
1173     $element['#prefix'] = '<div class="ajax-new-content">' . (isset($element['#prefix']) ? $element['#prefix'] : '');
1174     $element['#suffix'] = (isset($element['#suffix']) ? $element['#suffix'] : '') . '</div>';
1175
1176     return $element;
1177   }
1178
1179   /**
1180    * {@inheritdoc}
1181    */
1182   public function errorElement(array $element, ConstraintViolationInterface $error, array $form, FormStateInterface $form_state) {
1183     return $element;
1184   }
1185
1186   /**
1187    * Returns the value of a setting for the entity reference selection handler.
1188    *
1189    * @param string $setting_name
1190    *   The setting name.
1191    *
1192    * @return mixed
1193    *   The setting value.
1194    */
1195   protected function getSelectionHandlerSetting($setting_name) {
1196     $settings = $this->getFieldSetting('handler_settings');
1197     return isset($settings[$setting_name]) ? $settings[$setting_name] : NULL;
1198   }
1199
1200   /**
1201    * Checks whether a content entity is referenced.
1202    *
1203    * @return bool
1204    */
1205   protected function isContentReferenced() {
1206     $target_type = $this->getFieldSetting('target_type');
1207     $target_type_info = \Drupal::entityTypeManager()->getDefinition($target_type);
1208     return $target_type_info->isSubclassOf('\Drupal\Core\Entity\ContentEntityInterface');
1209   }
1210
1211   /**
1212    * {@inheritdoc}
1213    */
1214   public function elementValidate($element, FormStateInterface $form_state, $form) {
1215     $field_name = $this->fieldDefinition->getName();
1216     $widget_state = static::getWidgetState($element['#field_parents'], $field_name, $form_state);
1217     $delta = $element['#delta'];
1218
1219     if (isset($widget_state['paragraphs'][$delta]['entity'])) {
1220       $entity = $widget_state['paragraphs'][$delta]['entity'];
1221
1222       /** @var \Drupal\Core\Entity\Display\EntityFormDisplayInterface $display */
1223       $display = $widget_state['paragraphs'][$delta]['display'];
1224
1225       if ($widget_state['paragraphs'][$delta]['mode'] == 'edit') {
1226         // Extract the form values on submit for getting the current paragraph.
1227         $display->extractFormValues($entity, $element['subform'], $form_state);
1228         $display->validateFormValues($entity, $element['subform'], $form_state);
1229       }
1230     }
1231
1232     static::setWidgetState($element['#field_parents'], $field_name, $form_state, $widget_state);
1233   }
1234
1235   /**
1236    * {@inheritdoc}
1237    */
1238   public function massageFormValues(array $values, array $form, FormStateInterface $form_state) {
1239     $entity = $form_state->getFormObject()->getEntity();
1240     $field_name = $this->fieldDefinition->getName();
1241     $widget_state = static::getWidgetState($form['#parents'], $field_name, $form_state);
1242     $element = NestedArray::getValue($form_state->getCompleteForm(), $widget_state['array_parents']);
1243
1244     $new_revision = FALSE;
1245     if ($entity instanceof RevisionableInterface) {
1246       if ($entity->isNewRevision()) {
1247         $new_revision = TRUE;
1248       }
1249       // Most of the time we don't know yet if the host entity is going to be
1250       // saved as a new revision using RevisionableInterface::isNewRevision().
1251       // Most entity types (at least nodes) however use a boolean property named
1252       // "revision" to indicate whether a new revision should be saved. Use that
1253       // property.
1254       elseif ($entity->getEntityType()->hasKey('revision') && $form_state->getValue('revision')) {
1255         $new_revision = TRUE;
1256       }
1257     }
1258
1259     foreach ($values as $delta => &$item) {
1260       if (isset($widget_state['paragraphs'][$item['_original_delta']]['entity'])
1261         && $widget_state['paragraphs'][$item['_original_delta']]['mode'] != 'remove') {
1262         $paragraphs_entity = $widget_state['paragraphs'][$item['_original_delta']]['entity'];
1263
1264         /** @var \Drupal\Core\Entity\Display\EntityFormDisplayInterface $display */
1265         $display =  $widget_state['paragraphs'][$item['_original_delta']]['display'];
1266         if ($widget_state['paragraphs'][$item['_original_delta']]['mode'] == 'edit') {
1267           $display->extractFormValues($paragraphs_entity, $element[$item['_original_delta']]['subform'], $form_state);
1268         }
1269         $paragraphs_entity->setNewRevision($new_revision);
1270         // A content entity form saves without any rebuild. It needs to set the
1271         // language to update it in case of language change.
1272         $langcode_key = $paragraphs_entity->getEntityType()->getKey('langcode');
1273         if ($paragraphs_entity->get($langcode_key)->value != $form_state->get('langcode')) {
1274           // If a translation in the given language already exists, switch to
1275           // that. If there is none yet, update the language.
1276           if ($paragraphs_entity->hasTranslation($form_state->get('langcode'))) {
1277             $paragraphs_entity = $paragraphs_entity->getTranslation($form_state->get('langcode'));
1278           }
1279           else {
1280             $paragraphs_entity->set($langcode_key, $form_state->get('langcode'));
1281           }
1282         }
1283
1284         $paragraphs_entity->setNeedsSave(TRUE);
1285         $item['entity'] = $paragraphs_entity;
1286         $item['target_id'] = $paragraphs_entity->id();
1287         $item['target_revision_id'] = $paragraphs_entity->getRevisionId();
1288       }
1289       // If our mode is remove don't save or reference this entity.
1290       // @todo: Maybe we should actually delete it here?
1291       elseif($widget_state['paragraphs'][$item['_original_delta']]['mode'] == 'remove' || $widget_state['paragraphs'][$item['_original_delta']]['mode'] == 'removed') {
1292         $item['target_id'] = NULL;
1293         $item['target_revision_id'] = NULL;
1294       }
1295     }
1296     return $values;
1297   }
1298
1299   /**
1300    * {@inheritdoc}
1301    */
1302   public function extractFormValues(FieldItemListInterface $items, array $form, FormStateInterface $form_state) {
1303     // Filter possible empty items.
1304     $items->filterEmptyItems();
1305     return parent::extractFormValues($items, $form, $form_state);
1306   }
1307
1308   /**
1309    * Initializes the translation form state.
1310    *
1311    * @param \Drupal\Core\Form\FormStateInterface $form_state
1312    * @param \Drupal\Core\Entity\EntityInterface $host
1313    */
1314   protected function initIsTranslating(FormStateInterface $form_state, EntityInterface $host) {
1315     if ($this->isTranslating != NULL) {
1316       return;
1317     }
1318     $this->isTranslating = FALSE;
1319     if (!$host->isTranslatable()) {
1320       return;
1321     }
1322     if (!$host->getEntityType()->hasKey('default_langcode')) {
1323       return;
1324     }
1325     $default_langcode_key = $host->getEntityType()->getKey('default_langcode');
1326     if (!$host->hasField($default_langcode_key)) {
1327       return;
1328     }
1329
1330     if (!empty($form_state->get('content_translation'))) {
1331       // Adding a language through the ContentTranslationController.
1332       $this->isTranslating = TRUE;
1333     }
1334     if ($host->hasTranslation($form_state->get('langcode')) && $host->getTranslation($form_state->get('langcode'))->get($default_langcode_key)->value == 0) {
1335       // Editing a translation.
1336       $this->isTranslating = TRUE;
1337     }
1338   }
1339
1340   /**
1341    * After-build callback for removing the translatability clue from the widget.
1342    *
1343    * If the fields on the paragraph type are translatable,
1344    * ContentTranslationHandler::addTranslatabilityClue()adds an
1345    * "(all languages)" suffix to the widget title. That suffix is incorrect and
1346    * is being removed by this method using a #after_build on the field widget.
1347    *
1348    * @param array $element
1349    * @param \Drupal\Core\Form\FormStateInterface $form_state
1350    *
1351    * @return array
1352    */
1353   public static function removeTranslatabilityClue(array $element, FormStateInterface $form_state) {
1354     // Widgets could have multiple elements with their own titles, so remove the
1355     // suffix if it exists, do not recurse lower than this to avoid going into
1356     // nested paragraphs or similar nested field types.
1357     $suffix = ' <span class="translation-entity-all-languages">(' . t('all languages') . ')</span>';
1358     if (isset($element['#title']) && strpos($element['#title'], $suffix)) {
1359       $element['#title'] = str_replace($suffix, '', $element['#title']);
1360     }
1361     // Loop over all widget deltas.
1362     foreach (Element::children($element) as $delta) {
1363       if (isset($element[$delta]['#title']) && strpos($element[$delta]['#title'], $suffix)) {
1364         $element[$delta]['#title'] = str_replace($suffix, '', $element[$delta]['#title']);
1365       }
1366       // Loop over all form elements within the current delta.
1367       foreach (Element::children($element[$delta]) as $field) {
1368         if (isset($element[$delta][$field]['#title']) && strpos($element[$delta][$field]['#title'], $suffix)) {
1369           $element[$delta][$field]['#title'] = str_replace($suffix, '', $element[$delta][$field]['#title']);
1370         }
1371       }
1372     }
1373     return $element;
1374   }
1375
1376   /**
1377    * Returns the default paragraph type.
1378    *
1379    * @return string $default_paragraph_type
1380    *   Label name for default paragraph type.
1381    */
1382   protected function getDefaultParagraphTypeLabelName(){
1383     if ($this->getDefaultParagraphTypeMachineName() !== NULL) {
1384       $allowed_types = $this->getAllowedTypes();
1385       return $allowed_types[$this->getDefaultParagraphTypeMachineName()]['label'];
1386     }
1387
1388     return NULL;
1389   }
1390
1391   /**
1392    * Returns the machine name for default paragraph type.
1393    *
1394    * @return string
1395    *   Machine name for default paragraph type.
1396    */
1397   protected function getDefaultParagraphTypeMachineName() {
1398     $default_type = $this->getSetting('default_paragraph_type');
1399     $allowed_types = $this->getAllowedTypes();
1400     if ($default_type && isset($allowed_types[$default_type])) {
1401       return $default_type;
1402     }
1403     // Check if the user explicitly selected not to have any default Paragraph
1404     // type. Othewise, if there is only one type available, that one is the
1405     // default.
1406     if ($default_type === '_none') {
1407       return NULL;
1408     }
1409     if (count($allowed_types) === 1) {
1410       return key($allowed_types);
1411     }
1412
1413     return NULL;
1414   }
1415
1416   /**
1417    * @param \Drupal\paragraphs\Entity\Paragraph $paragraphs_entity
1418    *   Entity where to extract the values.
1419    *
1420    * @return string $collapsed_summary_text
1421    *   The text without tags to return.
1422    */
1423   public function addCollapsedSummary(paragraphs\Entity\Paragraph $paragraphs_entity) {
1424     $text_types = ['text_with_summary', 'text', 'text_long', 'list_string'];
1425     $summary = [];
1426     foreach ($paragraphs_entity->getFieldDefinitions() as $key => $value) {
1427       if ($value->getType() == 'image') {
1428         if ($paragraphs_entity->get($key)->entity) {
1429           foreach ($paragraphs_entity->get($key) as $image_key => $image_value) {
1430             if ($image_value->title != '') {
1431               $text = $image_value->title;
1432             }
1433             elseif ($image_value->alt != '') {
1434               $text = $image_value->alt;
1435             }
1436             elseif ($text = $image_value->entity->filename->value) {
1437               $text = $image_value->entity->filename->value;
1438             }
1439             if (strlen($text) > 50) {
1440               $text = strip_tags(substr($text, 0, 150));
1441             }
1442             $summary[] = $text;
1443           }
1444         }
1445       }
1446       if (in_array($value->getType(), $text_types)) {
1447         $text = $paragraphs_entity->get($key)->value;
1448         if (strlen($text) > 50) {
1449           $text = strip_tags(substr($text, 0, 150));
1450         }
1451         $summary[] = $text;
1452       }
1453       if ($field_type = $value->getType() == 'entity_reference_revisions') {
1454         if ($paragraphs_entity->get($key) && $paragraphs_entity->get($key)->entity) {
1455           $summary[] = $this->addCollapsedSummary($paragraphs_entity->get($key)->entity);
1456         }
1457       }
1458     }
1459     $collapsed_summary_text = implode(', ', $summary);
1460     return strip_tags($collapsed_summary_text);
1461   }
1462
1463   /**
1464    * {@inheritdoc}
1465    */
1466   public static function isApplicable(FieldDefinitionInterface $field_definition) {
1467     $target_type = $field_definition->getSetting('target_type');
1468     $paragraph_type = \Drupal::entityTypeManager()->getDefinition($target_type);
1469     if ($paragraph_type) {
1470       return $paragraph_type->isSubclassOf(ParagraphInterface::class);
1471     }
1472
1473     return FALSE;
1474   }
1475
1476 }