5a97c6db06d20125963ac67a7d4d857df86964eb
[yaffs-website] / web / modules / contrib / slick / src / Form / SlickAdmin.php
1 <?php
2
3 namespace Drupal\slick\Form;
4
5 use Drupal\Core\Url;
6 use Drupal\Core\Render\Element;
7 use Drupal\Component\Utility\Html;
8 use Drupal\Core\StringTranslation\StringTranslationTrait;
9 use Symfony\Component\DependencyInjection\ContainerInterface;
10 use Drupal\blazy\Dejavu\BlazyAdminExtended;
11 use Drupal\slick\SlickManagerInterface;
12
13 /**
14  * Provides resusable admin functions, or form elements.
15  */
16 class SlickAdmin implements SlickAdminInterface {
17
18   use StringTranslationTrait;
19
20   /**
21    * The blazy admin service.
22    *
23    * @var \Drupal\blazy\Dejavu\BlazyAdminExtended
24    */
25   protected $blazyAdmin;
26
27   /**
28    * The slick manager service.
29    *
30    * @var \Drupal\slick\SlickManagerInterface
31    */
32   protected $manager;
33
34   /**
35    * Constructs a SlickAdmin object.
36    *
37    * @param \Drupal\blazy\Dejavu\BlazyAdminExtended $blazy_admin
38    *   The blazy admin service.
39    * @param \Drupal\slick\SlickManagerInterface $manager
40    *   The slick manager service.
41    */
42   public function __construct(BlazyAdminExtended $blazy_admin, SlickManagerInterface $manager) {
43     $this->blazyAdmin = $blazy_admin;
44     $this->manager = $manager;
45   }
46
47   /**
48    * {@inheritdoc}
49    */
50   public static function create(ContainerInterface $container) {
51     return new static (
52       $container->get('blazy.admin.extended'),
53       $container->get('slick.manager')
54     );
55   }
56
57   /**
58    * Returns the blazy admin formatter.
59    */
60   public function blazyAdmin() {
61     return $this->blazyAdmin;
62   }
63
64   /**
65    * Returns the slick manager.
66    */
67   public function manager() {
68     return $this->manager;
69   }
70
71   /**
72    * Returns the main form elements.
73    */
74   public function buildSettingsForm(array &$form, $definition = []) {
75     $definition['caches']           = isset($definition['caches']) ? $definition['caches'] : TRUE;
76     $definition['namespace']        = 'slick';
77     $definition['optionsets']       = isset($definition['optionsets']) ? $definition['optionsets'] : $this->getOptionsetsByGroupOptions('main');
78     $definition['skins']            = isset($definition['skins']) ? $definition['skins'] : $this->getSkinsByGroupOptions('main');
79     $definition['responsive_image'] = isset($definition['responsive_image']) ? $definition['responsive_image'] : TRUE;
80
81     foreach (['optionsets', 'skins'] as $key) {
82       if (isset($definition[$key]['default'])) {
83         ksort($definition[$key]);
84         $definition[$key] = ['default' => $definition[$key]['default']] + $definition[$key];
85       }
86     }
87
88     if (empty($definition['no_layouts'])) {
89       $definition['layouts'] = isset($definition['layouts']) ? array_merge($this->getLayoutOptions(), $definition['layouts']) : $this->getLayoutOptions();
90     }
91
92     $this->openingForm($form, $definition);
93
94     if (!empty($definition['image_style_form']) && !isset($form['image_style'])) {
95       $this->imageStyleForm($form, $definition);
96     }
97
98     if (!empty($definition['media_switch_form']) && !isset($form['media_switch'])) {
99       $this->mediaSwitchForm($form, $definition);
100     }
101
102     if (!empty($definition['grid_form']) && !isset($form['grid'])) {
103       $this->gridForm($form, $definition);
104     }
105
106     if (!empty($definition['fieldable_form']) && !isset($form['image'])) {
107       $this->fieldableForm($form, $definition);
108     }
109
110     if (!empty($definition['breakpoints'])) {
111       $this->blazyAdmin->breakpointsForm($form, $definition);
112     }
113
114     if (!empty($definition['style']) && isset($form['style']['#description'])) {
115       $form['style']['#description'] .= ' ' . $this->t('CSS3 Columns is best with adaptiveHeight, non-vertical. Will use regular carousel as default style if left empty. Yet, both CSS3 Columns and Grid Foundation are respected as Grid displays when <strong>Grid large</strong> option is provided.');
116     }
117
118     $this->closingForm($form, $definition);
119   }
120
121   /**
122    * Returns the opening form elements.
123    */
124   public function openingForm(array &$form, $definition = []) {
125     $path         = drupal_get_path('module', 'slick');
126     $readme       = Url::fromUri('base:' . $path . '/README.txt')->toString();
127     $readme_field = Url::fromUri('base:' . $path . '/src/Plugin/Field/README.txt')->toString();
128     $arrows       = $this->getSkinsByGroupOptions('arrows');
129     $dots         = $this->getSkinsByGroupOptions('dots');
130
131     if (!isset($form['optionset'])) {
132       $this->blazyAdmin->openingForm($form, $definition);
133
134       $form['optionset']['#title'] = $this->t('Optionset main');
135
136       if ($this->manager()->getModuleHandler()->moduleExists('slick_ui')) {
137         $route_name = 'entity.slick.collection';
138         $form['optionset']['#description'] = $this->t('Manage optionsets at <a href=":url" target="_blank">the optionset admin page</a>.', [':url' => Url::fromRoute($route_name)->toString()]);
139       }
140     }
141
142     if (!empty($definition['nav']) || !empty($definition['thumbnails'])) {
143       $form['optionset_thumbnail'] = [
144         '#type'        => 'select',
145         '#title'       => $this->t('Optionset thumbnail'),
146         '#options'     => $this->getOptionsetsByGroupOptions('thumbnail'),
147         '#description' => $this->t('If provided, asNavFor aka thumbnail navigation applies. Leave empty to not use thumbnail navigation.'),
148         '#weight'      => -108,
149       ];
150
151       $form['skin_thumbnail'] = [
152         '#type'        => 'select',
153         '#title'       => $this->t('Skin thumbnail'),
154         '#options'     => $this->getSkinsByGroupOptions('thumbnail'),
155         '#description' => $this->t('Thumbnail navigation skin. See main <a href="@url" target="_blank">README</a> for details on Skins. Leave empty to not use thumbnail navigation.', ['@url' => $readme]),
156         '#weight'      => -106,
157       ];
158     }
159
160     if (count($arrows) > 0) {
161       $form['skin_arrows'] = [
162         '#type'        => 'select',
163         '#title'       => $this->t('Skin arrows'),
164         '#options'     => $arrows ?: [],
165         '#enforced'    => TRUE,
166         '#description' => $this->t('Implement \Drupal\slick\SlickSkinInterface::arrows() to add your own arrows skins, in the same format as SlickSkinInterface::skins().'),
167         '#weight'      => -105,
168       ];
169     }
170
171     if (count($dots) > 0) {
172       $form['skin_dots'] = [
173         '#type'        => 'select',
174         '#title'       => $this->t('Skin dots'),
175         '#options'     => $dots ?: [],
176         '#enforced'    => TRUE,
177         '#description' => $this->t('Implement \Drupal\slick\SlickSkinInterface::dots() to add your own dots skins, in the same format as SlickSkinInterface::skins().'),
178         '#weight'      => -105,
179       ];
180     }
181
182     if (!empty($definition['thumb_positions'])) {
183       $form['thumbnail_position'] = [
184         '#type'        => 'select',
185         '#title'       => $this->t('Thumbnail position'),
186         '#options' => [
187           'left'       => $this->t('Left'),
188           'right'      => $this->t('Right'),
189           'top'        => $this->t('Top'),
190           'over-left'  => $this->t('Overlay left'),
191           'over-right' => $this->t('Overlay right'),
192           'over-top'   => $this->t('Overlay top'),
193         ],
194         '#description' => $this->t('By default thumbnail is positioned at bottom. Hence to change the position of thumbnail. Only reasonable with 1 visible main stage at a time. Except any TOP, the rest requires Vertical option enabled for Optionset thumbnail, and a custom CSS height to selector <strong>.slick--thumbnail</strong> to avoid overflowing tall thumbnails, or adjust <strong>slidesToShow</strong> to fit the height. Further theming is required as usual. Overlay is absolutely positioned over the stage rather than sharing the space. See skin <strong>X VTabs</strong> for vertical thumbnail sample.'),
195         '#states' => [
196           'visible' => [
197             'select[name*="[optionset_thumbnail]"]' => ['!value' => ''],
198           ],
199         ],
200         '#weight'      => -99,
201       ];
202     }
203
204     if (!empty($definition['thumb_captions'])) {
205       $form['thumbnail_caption'] = [
206         '#type'        => 'select',
207         '#title'       => $this->t('Thumbnail caption'),
208         '#options'     => $definition['thumb_captions'],
209         '#description' => $this->t('Thumbnail caption maybe just title/ plain text. If Thumbnail image style is not provided, the thumbnail pagers will be just text like regular tabs.'),
210         '#states' => [
211           'visible' => [
212             'select[name*="[optionset_thumbnail]"]' => ['!value' => ''],
213           ],
214         ],
215         '#weight'      => 2,
216       ];
217     }
218
219     if (isset($form['skin'])) {
220       $form['skin']['#title'] = $this->t('Skin main');
221       $form['skin']['#description'] = $this->t('Skins allow various layouts with just CSS. Some options below depend on a skin. However a combination of skins and options may lead to unpredictable layouts, get yourself dirty. E.g.: Skin Split requires any split layout option. Failing to choose the expected layout makes it useless. See <a href=":url" target="_blank">SKINS section at README.txt</a> for details on Skins. Leave empty to DIY. Or use hook_slick_skins_info() and implement \Drupal\slick\SlickSkinInterface to register ones.', [':url' => $readme]);
222     }
223
224     if (isset($form['layout'])) {
225       $form['layout']['#description'] = $this->t('Requires a skin. The builtin layouts affects the entire slides uniformly. Split half requires any skin Split. See <a href="@url" target="_blank">README</a> under "Slide layout" for more info. Leave empty to DIY.', ['@url' => $readme_field]);
226     }
227
228     $weight = -99;
229     foreach (Element::children($form) as $key) {
230       if (!isset($form[$key]['#weight'])) {
231         $form[$key]['#weight'] = ++$weight;
232       }
233     }
234   }
235
236   /**
237    * Returns the image formatter form elements.
238    */
239   public function mediaSwitchForm(array &$form, $definition = []) {
240     $this->blazyAdmin->mediaSwitchForm($form, $definition);
241
242     if (isset($form['media_switch'])) {
243       $form['media_switch']['#description'] = $this->t('Depends on the enabled supported modules, or has known integration with Slick.<ol><li>Link to content: for aggregated small slicks.</li><li>Image to iframe: audio/video is hidden below image until toggled, otherwise iframe is always displayed, and draggable fails. Aspect ratio applies.</li><li>Colorbox.</li><li>Photobox. Be sure to select "Thumbnail style" for the overlay thumbnails.</li><li>Intense: image to fullscreen intense image.</li>');
244
245       if (!empty($definition['multimedia']) && isset($definition['fieldable_form'])) {
246         $form['media_switch']['#description'] .= ' ' . $this->t('<li>Image rendered by its formatter: image-related settings here will be ignored: breakpoints, image style, CSS background, aspect ratio, lazyload, etc. Only choose if needing a special image formatter such as Image Link Formatter.</li>');
247       }
248
249       $form['media_switch']['#description'] .= ' ' . $this->t('</ol> Try selecting "<strong>- None -</strong>" first before changing if trouble with this complex form states.');
250     }
251
252     if (isset($form['ratio']['#description'])) {
253       $form['ratio']['#description'] .= ' ' . $this->t('Required if using media entity to switch between iframe and overlay image, otherwise DIY.');
254     }
255   }
256
257   /**
258    * Returns the image formatter form elements.
259    */
260   public function imageStyleForm(array &$form, $definition = []) {
261     $definition['thumbnail_style'] = isset($definition['thumbnail_style']) ? $definition['thumbnail_style'] : TRUE;
262     $definition['ratios'] = isset($definition['ratios']) ? $definition['ratios'] : TRUE;
263
264     $definition['thumbnail_effect'] = [
265       'hover' => $this->t('Hoverable'),
266       'grid'  => $this->t('Static grid'),
267     ];
268
269     if (!isset($form['image_style'])) {
270       $this->blazyAdmin->imageStyleForm($form, $definition);
271
272       $form['image_style']['#description'] = $this->t('The main image style. This will be treated as the fallback image, which is normally smaller, if Breakpoints are provided, and if <strong>Use CSS background</strong> is disabled. Otherwise this is the only image displayed. Ignored by Responsive image option.');
273     }
274
275     if (isset($form['thumbnail_style'])) {
276       $form['thumbnail_style']['#description'] = $this->t('Usages: <ol><li>If <em>Optionset thumbnail</em> provided, it is for asNavFor thumbnail navigation.</li><li>For <em>Thumbnail effect</em>.</li><li>Photobox thumbnail.</li><li>Custom work via the provided data-thumb attributes: arrows with thumbnails, Photoswipe thumbnail, etc.</li></ol>Leave empty to not use thumbnails.');
277     }
278
279     if (isset($form['thumbnail_effect'])) {
280       $form['thumbnail_effect']['#description'] = $this->t('Dependent on a Skin, Dots and Thumbnail style options. No asnavfor/ Optionset thumbnail is needed. <ol><li><strong>Hoverable</strong>: Dots pager are kept, and thumbnail will be hidden and only visible on dot mouseover, default to min-width 120px.</li><li><strong>Static grid</strong>: Dots are hidden, and thumbnails are displayed as a static grid acting like dots pager.</li></ol>Alternative to asNavFor aka separate thumbnails as slider.');
281     }
282
283     if (isset($form['background'])) {
284       $form['background']['#description'] .= ' ' . $this->t('Works best with a single visible slide, skins full width/screen.');
285     }
286   }
287
288   /**
289    * Returns re-usable fieldable formatter form elements.
290    */
291   public function fieldableForm(array &$form, $definition = []) {
292     $this->blazyAdmin->fieldableForm($form, $definition);
293
294     if (isset($form['thumbnail'])) {
295       $form['thumbnail']['#description'] = $this->t("Only needed if <em>Optionset thumbnail</em> is provided. Maybe the same field as the main image, only different instance and image style. Leave empty to not use thumbnail pager.");
296     }
297
298     if (isset($form['overlay'])) {
299       $form['overlay']['#title'] = $this->t('Overlay media/slicks');
300       $form['overlay']['#description'] = $this->t('For audio/video, be sure the display is not image. For nested slicks, use the Slick carousel formatter for this field. Zebra layout is reasonable for overlay and captions.');
301     }
302   }
303
304   /**
305    * Returns re-usable grid elements across Slick field formatter and Views.
306    */
307   public function gridForm(array &$form, $definition = []) {
308     if (!isset($form['grid'])) {
309       $this->blazyAdmin->gridForm($form, $definition);
310     }
311
312     $header = $this->t('Group individual item as block grid?<small>An older alternative to core <strong>Rows</strong> option. Only works if the total items &gt; <strong>Visible slides</strong>. <br />block grid != slidesToShow option, yet both can work in tandem.<br />block grid = Rows option, yet the first is module feature, the later core.</small>');
313
314     $form['grid_header']['#markup'] = '<h3 class="form__title form__title--grid">' . $header . '</h3>';
315
316     $form['grid']['#description'] = $this->t('The amount of block grid columns for large monitors 64.063em - 90em. <br /><strong>Requires</strong>:<ol><li>Visible items,</li><li>Skin Grid for starter,</li><li>A reasonable amount of contents,</li><li>Optionset with Rows and slidesPerRow = 1.</li></ol>This is module feature, older than core Rows, and offers more flexibility. Leave empty to DIY, or to not build grids.');
317   }
318
319   /**
320    * Returns the closing ending form elements.
321    */
322   public function closingForm(array &$form, $definition = []) {
323     $form['override'] = [
324       '#title'       => $this->t('Override main optionset'),
325       '#type'        => 'checkbox',
326       '#description' => $this->t('If checked, the following options will override the main optionset. Useful to re-use one optionset for several different displays.'),
327       '#weight'      => 112,
328       '#enforced'    => TRUE,
329     ];
330
331     $form['overridables'] = [
332       '#type'        => 'checkboxes',
333       '#title'       => $this->t('Overridable options'),
334       '#description' => $this->t("Override the main optionset to re-use one. Anything dictated here will override the current main optionset. Unchecked means FALSE"),
335       '#options'     => $this->getOverridableOptions(),
336       '#weight'      => 113,
337       '#enforced'    => TRUE,
338       '#states' => [
339         'visible' => [
340           ':input[name$="[override]"]' => ['checked' => TRUE],
341         ],
342       ],
343     ];
344
345     $this->blazyAdmin->closingForm($form, $definition);
346   }
347
348   /**
349    * Returns overridable options to re-use one optionset.
350    */
351   public function getOverridableOptions() {
352     $options = [
353       'arrows'        => $this->t('Arrows'),
354       'autoplay'      => $this->t('Autoplay'),
355       'dots'          => $this->t('Dots'),
356       'draggable'     => $this->t('Draggable'),
357       'infinite'      => $this->t('Infinite'),
358       'mouseWheel'    => $this->t('Mousewheel'),
359       'randomize'     => $this->t('Randomize'),
360       'variableWidth' => $this->t('Variable width'),
361     ];
362
363     $this->manager->getModuleHandler()->alter('slick_overridable_options_info', $options);
364     return $options;
365   }
366
367   /**
368    * Returns default layout options for the core Image, or Views.
369    */
370   public function getLayoutOptions() {
371     return [
372       'bottom'      => $this->t('Caption bottom'),
373       'top'         => $this->t('Caption top'),
374       'right'       => $this->t('Caption right'),
375       'left'        => $this->t('Caption left'),
376       'center'      => $this->t('Caption center'),
377       'center-top'  => $this->t('Caption center top'),
378       'below'       => $this->t('Caption below the slide'),
379       'stage-right' => $this->t('Caption left, stage right'),
380       'stage-left'  => $this->t('Caption right, stage left'),
381       'split-right' => $this->t('Caption left, stage right, split half'),
382       'split-left'  => $this->t('Caption right, stage left, split half'),
383       'stage-zebra' => $this->t('Stage zebra'),
384       'split-zebra' => $this->t('Split half zebra'),
385     ];
386   }
387
388   /**
389    * Returns available slick optionsets by group.
390    */
391   public function getOptionsetsByGroupOptions($group = '') {
392     $optionsets = $groups = $ungroups = [];
393     $slicks = $this->manager->entityLoadMultiple('slick');
394     foreach ($slicks as $slick) {
395       $name = Html::escape($slick->label());
396       $id = $slick->id();
397       $current_group = $slick->getGroup();
398       if (!empty($group)) {
399         if ($current_group) {
400           if ($current_group != $group) {
401             continue;
402           }
403           $groups[$id] = $name;
404         }
405         else {
406           $ungroups[$id] = $name;
407         }
408       }
409       $optionsets[$id] = $name;
410     }
411
412     return $group ? array_merge($ungroups, $groups) : $optionsets;
413   }
414
415   /**
416    * Returns available slick skins for select options.
417    */
418   public function getSkinsByGroupOptions($group = '') {
419     return $this->manager->getSkinsByGroup($group, TRUE);
420   }
421
422   /**
423    * Return the field formatter settings summary.
424    *
425    * @deprecated: Removed for self::getSettingsSummary().
426    */
427   public function settingsSummary($plugin, $definition = []) {
428     return $this->blazyAdmin->settingsSummary($plugin, $definition);
429   }
430
431   /**
432    * Return the field formatter settings summary.
433    *
434    * @todo: Remove second param $plugin for post-release for Blazy RC2+.
435    */
436   public function getSettingsSummary($definition = [], $plugin = NULL) {
437     // @todo: Remove condition for Blazy RC2+.
438     if (!method_exists($this->blazyAdmin, 'getSettingsSummary')) {
439       return $this->blazyAdmin->settingsSummary($plugin, $definition);
440     }
441
442     return $this->blazyAdmin->getSettingsSummary($definition);
443   }
444
445   /**
446    * Returns available fields for select options.
447    */
448   public function getFieldOptions($target_bundles = [], $allowed_field_types = [], $entity_type_id = 'media', $target_type = '') {
449     return $this->blazyAdmin->getFieldOptions($target_bundles, $allowed_field_types, $entity_type_id, $target_type);
450   }
451
452   /**
453    * Returns re-usable logic, styling and assets across fields and Views.
454    */
455   public function finalizeForm(array &$form, $definition = []) {
456     $this->blazyAdmin->finalizeForm($form, $definition);
457   }
458
459 }