|
1
|
|
|
<?php |
|
2
|
|
|
|
|
3
|
|
|
namespace Drupal\paragraphs_editor\Plugin\Field\FieldWidget; |
|
4
|
|
|
|
|
5
|
|
|
use Drupal\Component\Utility\NestedArray; |
|
6
|
|
|
use Drupal\Core\Entity\EntityDisplayRepositoryInterface; |
|
7
|
|
|
use Drupal\Core\Entity\RevisionableInterface; |
|
8
|
|
|
use Drupal\Core\Entity\EntityFormInterface; |
|
9
|
|
|
use Drupal\Core\Field\FieldDefinitionInterface; |
|
10
|
|
|
use Drupal\Core\Field\FieldItemListInterface; |
|
11
|
|
|
use Drupal\Core\Form\FormStateInterface; |
|
12
|
|
|
use Drupal\Core\Plugin\ContainerFactoryPluginInterface; |
|
13
|
|
|
use Drupal\dom_processor\DomProcessor\DomProcessorInterface; |
|
14
|
|
|
use Drupal\paragraphs\Plugin\Field\FieldWidget\InlineParagraphsWidget; |
|
15
|
|
|
use Drupal\paragraphs_editor\EditorFieldValue\FieldValueManagerInterface; |
|
16
|
|
|
use Drupal\paragraphs_editor\Utility\TypeUtility; |
|
17
|
|
|
use Symfony\Component\DependencyInjection\ContainerInterface; |
|
18
|
|
|
|
|
19
|
|
|
/** |
|
20
|
|
|
* Plugin implementation of the 'entity_reference_paragraphs_editor' widget. |
|
21
|
|
|
* |
|
22
|
|
|
* @FieldWidget( |
|
23
|
|
|
* id = "entity_reference_paragraphs_editor", |
|
24
|
|
|
* label = @Translation("Paragraphs (Editor)"), |
|
25
|
|
|
* multiple_values = TRUE, |
|
26
|
|
|
* description = @Translation("Editor paragraphs form widget."), |
|
27
|
|
|
* field_types = { |
|
28
|
|
|
* "entity_reference_revisions" |
|
29
|
|
|
* } |
|
30
|
|
|
* ) |
|
31
|
|
|
*/ |
|
32
|
|
|
class ParagraphsEditorWidget extends InlineParagraphsWidget implements ContainerFactoryPluginInterface { |
|
33
|
|
|
|
|
34
|
|
|
/** |
|
35
|
|
|
* The editor field value manager for wrapping items. |
|
36
|
|
|
* |
|
37
|
|
|
* @var \Drupal\paragraphs_editor\EditorFieldValue\FieldValueManagerInterface |
|
38
|
|
|
*/ |
|
39
|
|
|
protected $fieldValueManager; |
|
40
|
|
|
|
|
41
|
|
|
/** |
|
42
|
|
|
* The dom processor for preparing and extracting editor content. |
|
43
|
|
|
* |
|
44
|
|
|
* @var \Drupal\dom_processor\DomProcessor\DomProcessorInterface |
|
45
|
|
|
*/ |
|
46
|
|
|
protected $domProcessor; |
|
47
|
|
|
|
|
48
|
|
|
/** |
|
49
|
|
|
* The plugin manager for bundle selector plugins. |
|
50
|
|
|
* |
|
51
|
|
|
* @var \Drupal\Component\Plugin\PluginManagerInterface |
|
52
|
|
|
*/ |
|
53
|
|
|
protected $bundleSelectorManager; |
|
54
|
|
|
|
|
55
|
|
|
/** |
|
56
|
|
|
* The plugin manager for delivery plugins. |
|
57
|
|
|
* |
|
58
|
|
|
* @var \Drupal\Component\Plugin\PluginManagerInterface |
|
59
|
|
|
*/ |
|
60
|
|
|
protected $deliveryProviderManager; |
|
61
|
|
|
|
|
62
|
|
|
/** |
|
63
|
|
|
* The entity display repository service for getting view modes. |
|
64
|
|
|
* |
|
65
|
|
|
* @var \Drupal\Core\Entity\EntityDisplayRepositoryInterface |
|
66
|
|
|
*/ |
|
67
|
|
|
protected $entityDisplayRepository; |
|
68
|
|
|
|
|
69
|
|
|
/** |
|
70
|
|
|
* Creates a paragraphs editor field widget. |
|
71
|
|
|
* |
|
72
|
|
|
* @param string $plugin_id |
|
73
|
|
|
* The field widget plugin id. |
|
74
|
|
|
* @param mixed $plugin_definition |
|
75
|
|
|
* The plugin definition. |
|
76
|
|
|
* @param \Drupal\Core\Field\FieldDefinitionInterface $field_definition |
|
77
|
|
|
* The paragraphs editor field definition. |
|
78
|
|
|
* @param array $settings |
|
79
|
|
|
* The paragraphs editor field widget settings. |
|
80
|
|
|
* @param array $third_party_settings |
|
81
|
|
|
* The third party settings for the widget. |
|
82
|
|
|
* @param \Drupal\paragraphs_editor\EditorFieldValue\FieldValueManagerInterface $field_value_manager |
|
83
|
|
|
* The field value manager for getting and setting paragraphs editor field |
|
84
|
|
|
* information. |
|
85
|
|
|
* @param \Drupal\dom_processor\DomProcessor\DomProcessorInterface $dom_processor |
|
86
|
|
|
* The DOM processor for reading and writing markup. |
|
87
|
|
|
* @param \Drupal\Core\Entity\EntityDisplayRepositoryInterface $entity_display_repository |
|
88
|
|
|
* The view mode manager. |
|
89
|
|
|
* @param array $plugin_managers |
|
90
|
|
|
* The paragraphs editor plugin managers. |
|
91
|
|
|
*/ |
|
92
|
|
|
public function __construct($plugin_id, $plugin_definition, FieldDefinitionInterface $field_definition, array $settings, array $third_party_settings, FieldValueManagerInterface $field_value_manager, DomProcessorInterface $dom_processor, EntityDisplayRepositoryInterface $entity_display_repository, array $plugin_managers) { |
|
93
|
|
|
parent::__construct($plugin_id, $plugin_definition, $field_definition, $settings, $third_party_settings); |
|
94
|
|
|
$this->fieldValueManager = $field_value_manager; |
|
95
|
|
|
$this->domProcessor = $dom_processor; |
|
96
|
|
|
$this->entityDisplayRepository = $entity_display_repository; |
|
97
|
|
|
$this->bundleSelectorManager = $plugin_managers['bundle_selector']; |
|
98
|
|
|
$this->deliveryProviderManager = $plugin_managers['delivery_provider']; |
|
99
|
|
|
} |
|
100
|
|
|
|
|
101
|
|
|
/** |
|
102
|
|
|
* {@inheritdoc} |
|
103
|
|
|
*/ |
|
104
|
|
|
public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) { |
|
105
|
|
|
$plugin_managers = []; |
|
106
|
|
|
foreach ($container->getParameter('paragraphs_editor.plugin_managers') as $name => $def) { |
|
107
|
|
|
$plugin_managers[$name] = $container->get($def->id); |
|
108
|
|
|
} |
|
109
|
|
|
return new static( |
|
110
|
|
|
$plugin_id, |
|
111
|
|
|
$plugin_definition, |
|
112
|
|
|
$configuration['field_definition'], |
|
113
|
|
|
$configuration['settings'], |
|
114
|
|
|
$configuration['third_party_settings'], |
|
115
|
|
|
$container->get('paragraphs_editor.field_value.manager'), |
|
116
|
|
|
$container->get('dom_processor.dom_processor'), |
|
117
|
|
|
$container->get('entity_display.repository'), |
|
118
|
|
|
$plugin_managers |
|
119
|
|
|
); |
|
120
|
|
|
} |
|
121
|
|
|
|
|
122
|
|
|
/** |
|
123
|
|
|
* {@inheritdoc} |
|
124
|
|
|
*/ |
|
125
|
|
|
public static function defaultSettings() { |
|
126
|
|
|
return [ |
|
127
|
|
|
'title' => t('Paragraph'), |
|
128
|
|
|
'bundle_selector' => 'list', |
|
129
|
|
|
'delivery_provider' => 'modal', |
|
130
|
|
|
'view_mode' => 'default', |
|
131
|
|
|
'prerender_count' => '10', |
|
132
|
|
|
]; |
|
133
|
|
|
} |
|
134
|
|
|
|
|
135
|
|
|
/** |
|
136
|
|
|
* {@inheritdoc} |
|
137
|
|
|
*/ |
|
138
|
|
|
public function formElement(FieldItemListInterface $items, $delta, array $element, array &$form, FormStateInterface $form_state) { |
|
139
|
|
|
$editable_data = $this->process('load', $items, $form_state); |
|
140
|
|
|
|
|
141
|
|
|
// Pretty much all the important parts are generated by the DOM processor. |
|
142
|
|
|
// Offloading things like '#attached' and '#attributes' to the processor |
|
143
|
|
|
// allows it to do things like dynamically load javascript for rendered |
|
144
|
|
|
// entities. |
|
145
|
|
|
return [ |
|
146
|
|
|
'markup' => $element + [ |
|
147
|
|
|
'#type' => 'text_format', |
|
148
|
|
|
'#format' => $editable_data->get('filter_format'), |
|
149
|
|
|
'#default_value' => $editable_data->get('markup'), |
|
150
|
|
|
'#rows' => 100, |
|
151
|
|
|
'#attributes' => $editable_data->get('attributes'), |
|
152
|
|
|
'#attached' => [ |
|
153
|
|
|
'library' => $editable_data->get('libraries'), |
|
154
|
|
|
'drupalSettings' => $editable_data->get('drupalSettings'), |
|
155
|
|
|
], |
|
156
|
|
|
'#allowed_formats' => [$editable_data->get('filter_format')], |
|
157
|
|
|
], |
|
158
|
|
|
'context_id' => [ |
|
159
|
|
|
'#type' => 'hidden', |
|
160
|
|
|
'#default_value' => $editable_data->get('context_id'), |
|
161
|
|
|
], |
|
162
|
|
|
]; |
|
163
|
|
|
} |
|
164
|
|
|
|
|
165
|
|
|
/** |
|
166
|
|
|
* {@inheritdoc} |
|
167
|
|
|
*/ |
|
168
|
|
|
public function settingsForm(array $form, FormStateInterface $form_state) { |
|
169
|
|
|
$elements = []; |
|
170
|
|
|
|
|
171
|
|
|
$elements['title'] = [ |
|
172
|
|
|
'#type' => 'textfield', |
|
173
|
|
|
'#title' => $this->t('Paragraph Title'), |
|
174
|
|
|
'#description' => $this->t('Label to appear as title on the button "Insert [title]. This label is translatable.'), |
|
175
|
|
|
'#default_value' => $this->getSetting('title'), |
|
176
|
|
|
'#required' => TRUE, |
|
177
|
|
|
]; |
|
178
|
|
|
|
|
179
|
|
|
$options = []; |
|
180
|
|
|
foreach ($this->bundleSelectorManager->getDefinitions() as $plugin) { |
|
181
|
|
|
$options[$plugin['id']] = $plugin['title']; |
|
182
|
|
|
} |
|
183
|
|
|
|
|
184
|
|
|
$elements['bundle_selector'] = [ |
|
185
|
|
|
'#type' => 'select', |
|
186
|
|
|
'#title' => $this->t('Bundle Selection Handler'), |
|
187
|
|
|
'#description' => $this->t('The bundle selector form plugin that will be used to allow users to insert paragraph items.'), |
|
188
|
|
|
'#options' => $options, |
|
189
|
|
|
'#default_value' => $this->getSetting('bundle_selector'), |
|
190
|
|
|
'#required' => TRUE, |
|
191
|
|
|
]; |
|
192
|
|
|
|
|
193
|
|
|
$options = []; |
|
194
|
|
|
foreach ($this->deliveryProviderManager->getDefinitions() as $plugin) { |
|
195
|
|
|
$options[$plugin['id']] = $plugin['title']; |
|
196
|
|
|
} |
|
197
|
|
|
|
|
198
|
|
|
$elements['delivery_provider'] = [ |
|
199
|
|
|
'#type' => 'select', |
|
200
|
|
|
'#title' => $this->t('Delivery Handler'), |
|
201
|
|
|
'#description' => $this->t('The delivery plugin that controls the user experience for how forms are delivered.'), |
|
202
|
|
|
'#options' => $options, |
|
203
|
|
|
'#default_value' => $this->getSetting('delivery_provider'), |
|
204
|
|
|
'#required' => TRUE, |
|
205
|
|
|
]; |
|
206
|
|
|
|
|
207
|
|
|
$elements['view_mode'] = [ |
|
208
|
|
|
'#type' => 'select', |
|
209
|
|
|
'#title' => 'Editor View Mode', |
|
210
|
|
|
'#description' => $this->t('The view mode that will be used to render embedded entities.'), |
|
211
|
|
|
'#options' => $this->entityDisplayRepository->getViewModeOptions('paragraph'), |
|
212
|
|
|
'#default_value' => $this->getSetting('prerender_count'), |
|
213
|
|
|
'#required' => TRUE, |
|
214
|
|
|
]; |
|
215
|
|
|
|
|
216
|
|
|
$options = [0 => $this->t('None')]; |
|
217
|
|
|
for ($i = 5; $i <= 50; $i += 5) { |
|
218
|
|
|
$options[$i] = $i; |
|
219
|
|
|
} |
|
220
|
|
|
$options[-1] = $this->t('All'); |
|
221
|
|
|
$elements['prerender_count'] = [ |
|
222
|
|
|
'#type' => 'select', |
|
223
|
|
|
'#title' => 'Maximum Pre-Render Items', |
|
224
|
|
|
'#description' => $this->t("The maximum number of embedded paragraphs to render before an editor is initialized. Additional entities will be rendered via ajax on demand, and won't be available to edit until their respective ajax calls finish."), |
|
225
|
|
|
'#options' => $options, |
|
226
|
|
|
'#default_value' => $this->getSetting('prerender_count'), |
|
227
|
|
|
'#required' => TRUE, |
|
228
|
|
|
]; |
|
229
|
|
|
|
|
230
|
|
|
return $elements; |
|
231
|
|
|
} |
|
232
|
|
|
|
|
233
|
|
|
/** |
|
234
|
|
|
* {@inheritdoc} |
|
235
|
|
|
*/ |
|
236
|
|
|
public function settingsSummary() { |
|
237
|
|
|
$bundle_selector = $this->bundleSelectorManager->getDefinition($this->getSetting('bundle_selector')); |
|
238
|
|
|
$delivery_provider = $this->deliveryProviderManager->getDefinition($this->getSetting('delivery_provider')); |
|
239
|
|
|
$prerender_count = $this->getSetting('prerender_count'); |
|
240
|
|
|
if ($prerender_count == '-1') { |
|
241
|
|
|
$prerender_count = 'All'; |
|
242
|
|
|
} |
|
243
|
|
|
elseif ($prerender_count == '0') { |
|
244
|
|
|
$prerender_count = 'None'; |
|
245
|
|
|
} |
|
246
|
|
|
$summary = []; |
|
247
|
|
|
$summary[] = $this->t('Title: @title', ['@title' => $this->getSetting('title')]); |
|
248
|
|
|
$summary[] = $this->t('Bundle Selector: @bundle_selector', ['@bundle_selector' => $bundle_selector['title']]); |
|
249
|
|
|
$summary[] = $this->t('Delivery Provider: @delivery_provider', ['@delivery_provider' => $delivery_provider['title']]); |
|
250
|
|
|
$summary[] = $this->t('View Mode: @mode', ['@mode' => $this->getSetting('view_mode')]); |
|
251
|
|
|
$summary[] = $this->t('Maximum Pre-Render Items: @prerender_count', ['@prerender_count' => $prerender_count]); |
|
252
|
|
|
return $summary; |
|
253
|
|
|
} |
|
254
|
|
|
|
|
255
|
|
|
/** |
|
256
|
|
|
* {@inheritdoc} |
|
257
|
|
|
*/ |
|
258
|
|
|
public function extractFormValues(FieldItemListInterface $items, array $form, FormStateInterface $form_state) { |
|
259
|
|
|
$field_name = $this->getFieldConfig()->getName(); |
|
260
|
|
|
$path = array_merge($form['#parents'], [$field_name]); |
|
261
|
|
|
$values = NestedArray::getValue($form_state->getValues(), $path); |
|
262
|
|
|
$this->process('update', $items, $form_state, $values['markup']['format'], $values['markup']['value'], $values['context_id']); |
|
263
|
|
|
} |
|
264
|
|
|
|
|
265
|
|
|
/** |
|
266
|
|
|
* {@inheritdoc} |
|
267
|
|
|
*/ |
|
268
|
|
|
public static function isApplicable(FieldDefinitionInterface $field_definition) { |
|
269
|
|
|
return \Drupal::service('paragraphs_editor.field_value.manager')->isParagraphsEditorField($field_definition); |
|
270
|
|
|
} |
|
271
|
|
|
|
|
272
|
|
|
/** |
|
273
|
|
|
* {@inheritdoc} |
|
274
|
|
|
*/ |
|
275
|
|
|
protected function mergeDefaults() { |
|
276
|
|
|
$this->settings += $this->getFieldConfig()->getThirdPartySettings('paragraphs_editor'); |
|
277
|
|
|
$this->settings += static::defaultSettings(); |
|
278
|
|
|
$this->defaultSettingsMerged = TRUE; |
|
279
|
|
|
} |
|
280
|
|
|
|
|
281
|
|
|
/** |
|
282
|
|
|
* Passes markup through the paragraphs_editor DOM processor. |
|
283
|
|
|
* |
|
284
|
|
|
* @param string $variant |
|
285
|
|
|
* The DOM Processor plugin variant to run: |
|
286
|
|
|
* - 'load' is used to take saved markup and make it editable. |
|
287
|
|
|
* - 'update' is used to take editor markup and make it saveable. |
|
288
|
|
|
* @param \Drupal\Core\Field\FieldItemListInterface $items |
|
289
|
|
|
* The field items that will receive savable entities, or serve loadable |
|
290
|
|
|
* entities. Note that neither of these operations perform entity saves. |
|
291
|
|
|
* @param \Drupal\Core\Form\FormStateInterface $form_state |
|
292
|
|
|
* The form state for the form that the field widget belongs to. |
|
293
|
|
|
* @param string|null $format |
|
294
|
|
|
* The default filter format name to apply to created text entities. |
|
295
|
|
|
* @param string|null $markup |
|
296
|
|
|
* The markup to be processed. Defaults to the markup inside the text |
|
297
|
|
|
* entity. |
|
298
|
|
|
* @param string|null $context_id |
|
299
|
|
|
* The id of the root editing context to pull edits from. |
|
300
|
|
|
* |
|
301
|
|
|
* @see \Drupal\paragraphs_editor\Plugin\dom_processor\data_processor\ParagraphsEditorPreparer |
|
302
|
|
|
* @see \Drupal\paragraphs_editor\Plugin\dom_processor\data_processor\ParagraphsEditorDecorator |
|
303
|
|
|
* @see \Drupal\paragraphs_editor\Plugin\dom_processor\data_processor\ParagraphsEditorExtractor |
|
304
|
|
|
* |
|
305
|
|
|
* @return \Drupal\dom_processor\DomProcessor\DomProcessorResultInterface |
|
306
|
|
|
* See the ParagraphsEditorDecorator and ParagraphsEditorExtractor DOM |
|
307
|
|
|
* Processor plugins for more information. |
|
308
|
|
|
*/ |
|
309
|
|
|
protected function process($variant, FieldItemListInterface $items, FormStateInterface $form_state, $format = NULL, $markup = NULL, $context_id = NULL) { |
|
310
|
|
|
$field_value_wrapper = $this->fieldValueManager->wrapItems($items); |
|
311
|
|
|
|
|
312
|
|
|
if (!isset($markup)) { |
|
313
|
|
|
$markup = $field_value_wrapper->getMarkup(); |
|
314
|
|
|
} |
|
315
|
|
|
|
|
316
|
|
|
if (!isset($format)) { |
|
317
|
|
|
$format = $field_value_wrapper->getFormat(); |
|
318
|
|
|
} |
|
319
|
|
|
|
|
320
|
|
|
if (empty($format)) { |
|
321
|
|
|
$format = $this->getFieldConfig()->getThirdPartySetting('paragraphs_editor', 'filter_format'); |
|
322
|
|
|
} |
|
323
|
|
|
|
|
324
|
|
|
// Ensure that we can get an entity to savethe updates to. |
|
325
|
|
|
$form_object = $form_state->getFormObject(); |
|
326
|
|
|
if (!$form_object instanceof EntityFormInterface) { |
|
327
|
|
|
throw new \Exception('Could not locate entity to save changes to in paragraphs editor widget.'); |
|
328
|
|
|
} |
|
329
|
|
|
|
|
330
|
|
|
// Check revisioning status. |
|
331
|
|
|
$entity = $form_object->getEntity(); |
|
332
|
|
|
$new_revision = FALSE; |
|
333
|
|
|
if ($entity instanceof RevisionableInterface) { |
|
334
|
|
|
if ($entity->isNewRevision()) { |
|
335
|
|
|
$new_revision = TRUE; |
|
336
|
|
|
} |
|
337
|
|
|
elseif ($entity->getEntityType()->hasKey('revision') && $form_state->getValue('revision')) { |
|
338
|
|
|
$new_revision = TRUE; |
|
339
|
|
|
} |
|
340
|
|
|
} |
|
341
|
|
|
|
|
342
|
|
|
return $this->domProcessor->process($markup, 'paragraphs_editor', $variant, [ |
|
343
|
|
|
'field' => [ |
|
344
|
|
|
'items' => $items, |
|
345
|
|
|
'context_id' => $context_id, |
|
346
|
|
|
'is_mutable' => TRUE, |
|
347
|
|
|
'wrapper' => $field_value_wrapper, |
|
348
|
|
|
], |
|
349
|
|
|
'owner' => [ |
|
350
|
|
|
'entity' => $entity, |
|
351
|
|
|
'new_revision' => $new_revision, |
|
352
|
|
|
], |
|
353
|
|
|
'langcode' => $form_state->get('langcode'), |
|
354
|
|
|
'settings' => $this->getSettings(), |
|
355
|
|
|
'filter_format' => $format, |
|
356
|
|
|
]); |
|
357
|
|
|
} |
|
358
|
|
|
|
|
359
|
|
|
/** |
|
360
|
|
|
* Safely gets the field config associated with this widget. |
|
361
|
|
|
* |
|
362
|
|
|
* @return \Drupal\Core\Field\FieldConfigInterface |
|
363
|
|
|
* The field config object. |
|
364
|
|
|
*/ |
|
365
|
|
|
protected function getFieldConfig() { |
|
366
|
|
|
return TypeUtility::ensureFieldConfig($this->fieldDefinition); |
|
367
|
|
|
} |
|
368
|
|
|
|
|
369
|
|
|
} |
|
370
|
|
|
|