1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
namespace Drupal\entity_browser\Plugin\EntityBrowser\Display; |
4
|
|
|
|
5
|
|
|
use Drupal\Component\Utility\Html; |
6
|
|
|
use Drupal\Component\Utility\NestedArray; |
7
|
|
|
use Drupal\Component\Uuid\UuidInterface; |
8
|
|
|
use Drupal\Core\Ajax\OpenDialogCommand; |
9
|
|
|
use Drupal\Core\Entity\EntityInterface; |
10
|
|
|
use Drupal\Core\KeyValueStore\KeyValueStoreExpirableInterface; |
11
|
|
|
use Drupal\Core\Routing\RouteMatchInterface; |
12
|
|
|
use Drupal\Core\Url; |
13
|
|
|
use Drupal\entity_browser\DisplayBase; |
14
|
|
|
use Drupal\entity_browser\DisplayRouterInterface; |
15
|
|
|
use Drupal\entity_browser\Events\Events; |
16
|
|
|
use Drupal\entity_browser\Events\RegisterJSCallbacks; |
17
|
|
|
use Symfony\Component\DependencyInjection\ContainerInterface; |
18
|
|
|
use Symfony\Component\EventDispatcher\EventDispatcherInterface; |
19
|
|
|
use Drupal\Core\Path\CurrentPathStack; |
20
|
|
|
use Drupal\Core\Ajax\AjaxResponse; |
21
|
|
|
use Symfony\Component\HttpKernel\Event\FilterResponseEvent; |
22
|
|
|
use Drupal\Core\Form\FormStateInterface; |
23
|
|
|
use Symfony\Component\HttpFoundation\Request; |
24
|
|
|
use Symfony\Component\HttpFoundation\Response; |
25
|
|
|
use Drupal\entity_browser\Events\AlterEntityBrowserDisplayData; |
26
|
|
|
|
27
|
|
|
/** |
28
|
|
|
* Presents entity browser in an Modal. |
29
|
|
|
* |
30
|
|
|
* @EntityBrowserDisplay( |
31
|
|
|
* id = "modal", |
32
|
|
|
* label = @Translation("Modal"), |
33
|
|
|
* description = @Translation("Displays the entity browser in a modal window."), |
34
|
|
|
* uses_route = TRUE |
35
|
|
|
* ) |
36
|
|
|
*/ |
37
|
|
|
class Modal extends DisplayBase implements DisplayRouterInterface { |
38
|
|
|
|
39
|
|
|
/** |
40
|
|
|
* Current route match service. |
41
|
|
|
* |
42
|
|
|
* @var \Drupal\Core\Routing\RouteMatchInterface |
43
|
|
|
*/ |
44
|
|
|
protected $currentRouteMatch; |
45
|
|
|
|
46
|
|
|
/** |
47
|
|
|
* Current path. |
48
|
|
|
* |
49
|
|
|
* @var \Drupal\Core\Path\CurrentPathStack |
50
|
|
|
*/ |
51
|
|
|
protected $currentPath; |
52
|
|
|
|
53
|
|
|
/** |
54
|
|
|
* Current request. |
55
|
|
|
* |
56
|
|
|
* @var \Symfony\Component\HttpFoundation\Request |
57
|
|
|
*/ |
58
|
|
|
protected $request; |
59
|
|
|
|
60
|
|
|
/** |
61
|
|
|
* Constructs display plugin. |
62
|
|
|
* |
63
|
|
|
* @param array $configuration |
64
|
|
|
* A configuration array containing information about the plugin instance. |
65
|
|
|
* @param string $plugin_id |
66
|
|
|
* The plugin_id for the plugin instance. |
67
|
|
|
* @param mixed $plugin_definition |
68
|
|
|
* The plugin implementation definition. |
69
|
|
|
* @param \Symfony\Component\EventDispatcher\EventDispatcherInterface $event_dispatcher |
70
|
|
|
* Event dispatcher service. |
71
|
|
|
* @param \Drupal\Component\Uuid\UuidInterface $uuid |
72
|
|
|
* UUID generator interface. |
73
|
|
|
* @param \Drupal\Core\KeyValueStore\KeyValueStoreExpirableInterface $selection_storage |
74
|
|
|
* The selection storage. |
75
|
|
|
* @param \Drupal\Core\Routing\RouteMatchInterface $current_route_match |
76
|
|
|
* The currently active route match object. |
77
|
|
|
* @param \Drupal\Core\Path\CurrentPathStack $current_path |
78
|
|
|
* The current path. |
79
|
|
|
* @param \Symfony\Component\HttpFoundation\Request $request |
80
|
|
|
* Current request. |
81
|
|
|
*/ |
82
|
|
|
public function __construct(array $configuration, $plugin_id, $plugin_definition, EventDispatcherInterface $event_dispatcher, UuidInterface $uuid, KeyValueStoreExpirableInterface $selection_storage, RouteMatchInterface $current_route_match, CurrentPathStack $current_path, Request $request) { |
83
|
|
|
parent::__construct($configuration, $plugin_id, $plugin_definition, $event_dispatcher, $uuid, $selection_storage); |
84
|
|
|
$this->currentRouteMatch = $current_route_match; |
85
|
|
|
$this->currentPath = $current_path; |
86
|
|
|
$this->request = $request; |
87
|
|
|
} |
88
|
|
|
|
89
|
|
|
/** |
90
|
|
|
* {@inheritdoc} |
91
|
|
|
*/ |
92
|
|
View Code Duplication |
public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) { |
|
|
|
|
93
|
|
|
return new static( |
94
|
|
|
$configuration, |
95
|
|
|
$plugin_id, |
96
|
|
|
$plugin_definition, |
97
|
|
|
$container->get('event_dispatcher'), |
98
|
|
|
$container->get('uuid'), |
99
|
|
|
$container->get('entity_browser.selection_storage'), |
100
|
|
|
$container->get('current_route_match'), |
101
|
|
|
$container->get('path.current'), |
102
|
|
|
$container->get('request_stack')->getCurrentRequest() |
103
|
|
|
); |
104
|
|
|
} |
105
|
|
|
|
106
|
|
|
/** |
107
|
|
|
* {@inheritdoc} |
108
|
|
|
*/ |
109
|
|
View Code Duplication |
public function defaultConfiguration() { |
|
|
|
|
110
|
|
|
return [ |
111
|
|
|
'width' => '650', |
112
|
|
|
'height' => '500', |
113
|
|
|
'link_text' => $this->t('Select entities'), |
114
|
|
|
'auto_open' => FALSE, |
115
|
|
|
] + parent::defaultConfiguration(); |
116
|
|
|
} |
117
|
|
|
|
118
|
|
|
/** |
119
|
|
|
* {@inheritdoc} |
120
|
|
|
*/ |
121
|
|
|
public function displayEntityBrowser(array $element, FormStateInterface $form_state, array &$complete_form, array $persistent_data = []) { |
122
|
|
|
parent::displayEntityBrowser($element, $form_state, $complete_form, $persistent_data); |
123
|
|
|
$js_event_object = new RegisterJSCallbacks($this->configuration['entity_browser_id'], $this->getUuid()); |
124
|
|
|
$js_event_object->registerCallback('Drupal.entityBrowser.selectionCompleted'); |
125
|
|
|
$js_event = $this->eventDispatcher->dispatch(Events::REGISTER_JS_CALLBACKS, $js_event_object); |
126
|
|
|
$original_path = $this->currentPath->getPath(); |
127
|
|
|
|
128
|
|
|
$data = [ |
129
|
|
|
'query_parameters' => [ |
130
|
|
|
'query' => [ |
131
|
|
|
'uuid' => $this->getUuid(), |
132
|
|
|
'original_path' => $original_path, |
133
|
|
|
], |
134
|
|
|
], |
135
|
|
|
'attributes' => [ |
136
|
|
|
'data-uuid' => $this->getUuid(), |
137
|
|
|
], |
138
|
|
|
]; |
139
|
|
|
$event_object = new AlterEntityBrowserDisplayData($this->configuration['entity_browser_id'], $this->getUuid(), $this->getPluginDefinition(), $form_state, $data); |
140
|
|
|
$event = $this->eventDispatcher->dispatch(Events::ALTER_BROWSER_DISPLAY_DATA, $event_object); |
141
|
|
|
$data = $event->getData(); |
142
|
|
|
return [ |
143
|
|
|
'#theme_wrappers' => ['container'], |
144
|
|
|
'path' => [ |
145
|
|
|
'#type' => 'hidden', |
146
|
|
|
'#value' => Url::fromRoute('entity_browser.' . $this->configuration['entity_browser_id'], [], $data['query_parameters'])->toString(), |
147
|
|
|
], |
148
|
|
|
'open_modal' => [ |
149
|
|
|
'#type' => 'submit', |
150
|
|
|
'#value' => $this->configuration['link_text'], |
151
|
|
|
'#limit_validation_errors' => [], |
152
|
|
|
'#submit' => [], |
153
|
|
|
'#name' => implode('_', $element['#eb_parents']), |
154
|
|
|
'#ajax' => [ |
155
|
|
|
'callback' => [$this, 'openModal'], |
156
|
|
|
'event' => 'click', |
157
|
|
|
], |
158
|
|
|
'#executes_submit_callback' => FALSE, |
159
|
|
|
'#attributes' => $data['attributes'], |
160
|
|
|
'#attached' => [ |
161
|
|
|
'library' => ['core/drupal.dialog.ajax', 'entity_browser/modal'], |
162
|
|
|
'drupalSettings' => [ |
163
|
|
|
'entity_browser' => [ |
164
|
|
|
'modal' => [ |
165
|
|
|
$this->getUuid() => [ |
166
|
|
|
'uuid' => $this->getUuid(), |
167
|
|
|
'js_callbacks' => $js_event->getCallbacks(), |
168
|
|
|
'original_path' => $original_path, |
169
|
|
|
'auto_open' => $this->configuration['auto_open'], |
170
|
|
|
], |
171
|
|
|
], |
172
|
|
|
], |
173
|
|
|
], |
174
|
|
|
], |
175
|
|
|
], |
176
|
|
|
]; |
177
|
|
|
} |
178
|
|
|
|
179
|
|
|
/** |
180
|
|
|
* Generates the content and opens the modal. |
181
|
|
|
* |
182
|
|
|
* @param array $form |
183
|
|
|
* The form array. |
184
|
|
|
* @param \Drupal\Core\Form\FormStateInterface $form_state |
185
|
|
|
* The form state object. |
186
|
|
|
* |
187
|
|
|
* @return \Drupal\Core\Ajax\AjaxResponse |
188
|
|
|
* An ajax response. |
189
|
|
|
*/ |
190
|
|
|
public function openModal(array &$form, FormStateInterface $form_state) { |
191
|
|
|
$triggering_element = $form_state->getTriggeringElement(); |
192
|
|
|
$parents = $triggering_element['#parents']; |
193
|
|
|
array_pop($parents); |
194
|
|
|
$parents = array_merge($parents, ['path']); |
195
|
|
|
$input = $form_state->getUserInput(); |
196
|
|
|
$src = NestedArray::getValue($input, $parents); |
197
|
|
|
|
198
|
|
|
$field_name = $triggering_element['#parents'][0]; |
199
|
|
|
$element_name = $this->configuration['entity_browser_id']; |
200
|
|
|
$name = 'entity_browser_iframe_' . $element_name; |
201
|
|
|
$content = [ |
202
|
|
|
'#type' => 'html_tag', |
203
|
|
|
'#tag' => 'iframe', |
204
|
|
|
'#attributes' => [ |
205
|
|
|
'src' => $src, |
206
|
|
|
'class' => 'entity-browser-modal-iframe', |
207
|
|
|
'width' => '100%', |
208
|
|
|
'height' => $this->configuration['height'] - 90, |
209
|
|
|
'frameborder' => 0, |
210
|
|
|
'style' => 'padding:0', |
211
|
|
|
'name' => $name, |
212
|
|
|
'id' => $name, |
213
|
|
|
], |
214
|
|
|
]; |
215
|
|
|
$html = drupal_render($content); |
216
|
|
|
|
217
|
|
|
$response = new AjaxResponse(); |
218
|
|
|
$response->addCommand(new OpenDialogCommand('#' . Html::getUniqueId($field_name . '-' . $element_name . '-dialog'), $this->configuration['link_text'], $html, [ |
219
|
|
|
'width' => 'auto', |
220
|
|
|
'height' => 'auto', |
221
|
|
|
'modal' => TRUE, |
222
|
|
|
'maxWidth' => $this->configuration['width'], |
223
|
|
|
'maxHeight' => $this->configuration['height'], |
224
|
|
|
'fluid' => 1, |
225
|
|
|
'autoResize' => 0, |
226
|
|
|
'resizable' => 0, |
227
|
|
|
])); |
228
|
|
|
return $response; |
229
|
|
|
} |
230
|
|
|
|
231
|
|
|
/** |
232
|
|
|
* KernelEvents::RESPONSE listener. |
233
|
|
|
* |
234
|
|
|
* Intercepts default response and injects |
235
|
|
|
* response that will trigger JS to propagate selected entities upstream. |
236
|
|
|
* |
237
|
|
|
* @param FilterResponseEvent $event |
238
|
|
|
* Response event. |
239
|
|
|
*/ |
240
|
|
View Code Duplication |
public function propagateSelection(FilterResponseEvent $event) { |
|
|
|
|
241
|
|
|
$render = [ |
242
|
|
|
'labels' => [ |
243
|
|
|
'#markup' => 'Labels: ' . implode(', ', array_map(function (EntityInterface $item) { |
244
|
|
|
return $item->label(); |
245
|
|
|
}, $this->entities)), |
246
|
|
|
'#attached' => [ |
247
|
|
|
'library' => ['entity_browser/modal_selection'], |
248
|
|
|
'drupalSettings' => [ |
249
|
|
|
'entity_browser' => [ |
250
|
|
|
'modal' => [ |
251
|
|
|
'entities' => array_map(function (EntityInterface $item) { |
252
|
|
|
return [$item->id(), $item->uuid(), $item->getEntityTypeId()]; |
253
|
|
|
}, $this->entities), |
254
|
|
|
'uuid' => $this->request->query->get('uuid'), |
255
|
|
|
], |
256
|
|
|
], |
257
|
|
|
], |
258
|
|
|
], |
259
|
|
|
], |
260
|
|
|
]; |
261
|
|
|
|
262
|
|
|
$event->setResponse(new Response(\Drupal::service('bare_html_page_renderer')->renderBarePage($render, 'Entity browser', 'page'))); |
263
|
|
|
} |
264
|
|
|
|
265
|
|
|
/** |
266
|
|
|
* {@inheritdoc} |
267
|
|
|
*/ |
268
|
|
|
public function path() { |
269
|
|
|
return '/entity-browser/modal/' . $this->configuration['entity_browser_id']; |
270
|
|
|
} |
271
|
|
|
|
272
|
|
|
/** |
273
|
|
|
* {@inheritdoc} |
274
|
|
|
*/ |
275
|
|
|
public function __sleep() { |
276
|
|
|
return ['configuration']; |
277
|
|
|
} |
278
|
|
|
|
279
|
|
|
/** |
280
|
|
|
* {@inheritdoc} |
281
|
|
|
*/ |
282
|
|
|
public function buildConfigurationForm(array $form, FormStateInterface $form_state) { |
283
|
|
|
$configuration = $this->getConfiguration(); |
284
|
|
|
$form['width'] = [ |
285
|
|
|
'#type' => 'number', |
286
|
|
|
'#title' => $this->t('Width of the modal'), |
287
|
|
|
'#default_value' => $configuration['width'], |
288
|
|
|
'#description' => $this->t('Empty value for responsive width.'), |
289
|
|
|
]; |
290
|
|
|
$form['height'] = [ |
291
|
|
|
'#type' => 'number', |
292
|
|
|
'#title' => $this->t('Height of the modal'), |
293
|
|
|
'#default_value' => $configuration['height'], |
294
|
|
|
'#description' => $this->t('Empty value for responsive height.'), |
295
|
|
|
]; |
296
|
|
|
$form['link_text'] = [ |
297
|
|
|
'#type' => 'textfield', |
298
|
|
|
'#title' => $this->t('Link text'), |
299
|
|
|
'#default_value' => $configuration['link_text'], |
300
|
|
|
]; |
301
|
|
|
$form['auto_open'] = [ |
302
|
|
|
'#type' => 'checkbox', |
303
|
|
|
'#title' => $this->t('Auto open entity browser'), |
304
|
|
|
'#default_value' => $configuration['auto_open'], |
305
|
|
|
'#description' => $this->t('Will open Entity browser modal as soon as page is loaded, which might cause unwanted results. Should be used only in very specific cases such as Inline entity form integration. It is also advised not to use Entity browsers with this option enabled more than once per page.'), |
306
|
|
|
]; |
307
|
|
|
return $form; |
308
|
|
|
} |
309
|
|
|
|
310
|
|
|
} |
311
|
|
|
|
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.
You can also find more detailed suggestions in the “Code” section of your repository.