Yaffs site version 1.1
[yaffs-website] / web / modules / contrib / slick / slick_ui / src / Form / SlickForm.php
1 <?php
2
3 namespace Drupal\slick_ui\Form;
4
5 use Drupal\Core\Form\FormStateInterface;
6 use Drupal\slick\Entity\Slick;
7
8 /**
9  * Extends base form for slick instance configuration form.
10  */
11 class SlickForm extends SlickFormBase {
12
13   /**
14    * The form elements.
15    *
16    * @var array
17    */
18   protected $formElements;
19
20   /**
21    * {@inheritdoc}
22    */
23   public function form(array $form, FormStateInterface $form_state) {
24     $form      = parent::form($form, $form_state);
25     $slick     = $this->entity;
26     $options   = $slick->getOptions() ?: [];
27     $admin_css = $this->manager->configLoad('admin_css', 'blazy.settings');
28     $tooltip   = ['class' => ['is-tooltip']];
29
30     // Options.
31     $form['options'] = [
32       '#type'    => 'vertical_tabs',
33       '#tree'    => TRUE,
34       '#parents' => ['options'],
35     ];
36
37     // Main JS options.
38     $form['settings'] = [
39       '#type'       => 'details',
40       '#tree'       => TRUE,
41       '#title'      => $this->t('Settings'),
42       '#attributes' => ['class' => ['details--settings', 'has-tooltip']],
43       '#group'      => 'options',
44       '#parents'    => ['options', 'settings'],
45     ];
46
47     foreach ($this->getFormElements() as $name => $element) {
48       $element['default'] = isset($element['default']) ? $element['default'] : '';
49       $form['settings'][$name] = [
50         '#title'         => isset($element['title']) ? $element['title'] : '',
51         '#default_value' => (NULL !== $slick->getSetting($name)) ? $slick->getSetting($name) : $element['default'],
52       ];
53
54       if (isset($element['type'])) {
55         $form['settings'][$name]['#type'] = $element['type'];
56         if ($element['type'] != 'hidden') {
57           $form['settings'][$name]['#attributes'] = $tooltip;
58         }
59         else {
60           // Ensures hidden element doesn't screw up the states.
61           unset($element['states']);
62         }
63
64         if ($element['type'] == 'textfield') {
65           $form['settings'][$name]['#size'] = 20;
66           $form['settings'][$name]['#maxlength'] = 255;
67         }
68       }
69
70       if (isset($element['options'])) {
71         $form['settings'][$name]['#options'] = $element['options'];
72       }
73
74       if (isset($element['empty_option'])) {
75         $form['settings'][$name]['#empty_option'] = $element['empty_option'];
76       }
77
78       if (isset($element['description'])) {
79         $form['settings'][$name]['#description'] = $element['description'];
80       }
81
82       if (isset($element['states'])) {
83         $form['settings'][$name]['#states'] = $element['states'];
84       }
85
86       // Expand textfield for easy edit.
87       if (in_array($name, ['prevArrow', 'nextArrow'])) {
88         $form['settings'][$name]['#attributes']['class'][] = 'js-expandable';
89       }
90
91       if (isset($element['field_suffix'])) {
92         $form['settings'][$name]['#field_suffix'] = $element['field_suffix'];
93       }
94
95       if (is_int($element['default'])) {
96         $form['settings'][$name]['#maxlength'] = 60;
97         $form['settings'][$name]['#attributes']['class'][] = 'form-text--int';
98       }
99
100       if ($admin_css && !isset($element['field_suffix']) && is_bool($element['default'])) {
101         $form['settings'][$name]['#field_suffix'] = '&nbsp;';
102         $form['settings'][$name]['#title_display'] = 'before';
103       }
104     }
105
106     // Responsive JS options.
107     // https://github.com/kenwheeler/slick/issues/951
108     $form['responsives'] = [
109       '#type'        => 'details',
110       '#title'       => $this->t('Responsive display'),
111       '#open'        => TRUE,
112       '#tree'        => TRUE,
113       '#group'       => 'options',
114       '#parents'     => ['options', 'responsives'],
115       '#description' => $this->t('Containing breakpoints and settings objects. Settings set at a given breakpoint/screen width is self-contained and does not inherit the main settings, but defaults. Be sure to set Breakpoints option above.'),
116     ];
117
118     $form['responsives']['responsive'] = [
119       '#type'       => 'details',
120       '#title'      => $this->t('Responsive'),
121       '#open'       => TRUE,
122       '#group'      => 'responsives',
123       '#parents'    => ['options', 'responsives', 'responsive'],
124       '#prefix'     => '<div id="edit-breakpoints-ajax-wrapper">',
125       '#suffix'     => '</div>',
126       '#attributes' => ['class' => ['has-tooltip', 'details--responsive--ajax']],
127     ];
128
129     // Add some information to the form state for easier form altering.
130     $form_state->set('breakpoints_count', 0);
131     $breakpoints_count = $form_state->hasValue('breakpoints') ? $form_state->getValue('breakpoints') : $slick->getBreakpoints();
132
133     if (!$form_state->hasValue('breakpoints_count')) {
134       $form_state->setValue('breakpoints_count', $breakpoints_count);
135     }
136
137     $user_input = $form_state->getUserInput();
138     $breakpoints_input = isset($user_input['breakpoints']) ? (int) $user_input['breakpoints'] : $breakpoints_count;
139
140     if ($breakpoints_input && ($breakpoints_input != $breakpoints_count)) {
141       $form_state->setValue('breakpoints_count', $breakpoints_input);
142     }
143
144     if ($form_state->getValue('breakpoints_count') > 0) {
145       $slick_responsive_options = $this->getResponsiveFormElements($form_state->getValue('breakpoints_count'));
146
147       foreach ($slick_responsive_options as $i => $responsives) {
148         // Individual breakpoint details depends on the breakpoints amount.
149         $form['responsives']['responsive'][$i] = [
150           '#type'       => $responsives['type'],
151           '#title'      => $responsives['title'],
152           '#open'       => FALSE,
153           '#group'      => 'responsive',
154           '#attributes' => [
155             'class' => [
156               'details--responsive',
157               'details--breakpoint-' . $i,
158               'has-tooltip',
159             ],
160           ],
161         ];
162
163         unset($responsives['title'], $responsives['type']);
164         foreach ($responsives as $key => $responsive) {
165           switch ($key) {
166             case 'breakpoint':
167             case 'unslick':
168               $form['responsives']['responsive'][$i][$key] = [
169                 '#type'          => $responsive['type'],
170                 '#title'         => $responsive['title'],
171                 '#default_value' => isset($options['responsives']['responsive'][$i][$key]) ? $options['responsives']['responsive'][$i][$key] : $responsive['default'],
172                 '#description'   => $responsive['description'],
173                 '#attributes'    => $tooltip,
174               ];
175
176               if ($responsive['type'] == 'textfield') {
177                 $form['responsives']['responsive'][$i][$key]['#size'] = 20;
178                 $form['responsives']['responsive'][$i][$key]['#maxlength'] = 255;
179               }
180
181               if (is_int($responsive['default'])) {
182                 $form['responsives']['responsive'][$i][$key]['#maxlength'] = 60;
183               }
184
185               if (isset($responsive['field_suffix'])) {
186                 $form['responsives']['responsive'][$i][$key]['#field_suffix'] = $responsive['field_suffix'];
187               }
188
189               if ($admin_css && !isset($responsive['field_suffix']) && $responsive['type'] == 'checkbox') {
190                 $form['responsives']['responsive'][$i][$key]['#field_suffix'] = '&nbsp;';
191                 $form['responsives']['responsive'][$i][$key]['#title_display'] = 'before';
192               }
193               break;
194
195             case 'settings':
196               $form['responsives']['responsive'][$i][$key] = [
197                 '#type'       => $responsive['type'],
198                 '#title'      => $responsive['title'],
199                 '#open'       => TRUE,
200                 '#group'      => $i,
201                 '#states'     => ['visible' => [':input[name*="[responsive][' . $i . '][unslick]"]' => ['checked' => FALSE]]],
202                 '#attributes' => [
203                   'class' => [
204                     'details--settings',
205                     'details--breakpoint-' . $i,
206                     'has-tooltip',
207                   ],
208                 ],
209               ];
210
211               unset($responsive['title'], $responsive['type']);
212
213               // @fixme, boolean default is ignored at index 0 only.
214               foreach ($responsive as $k => $item) {
215                 $item['default'] = isset($item['default']) ? $item['default'] : '';
216                 $form['responsives']['responsive'][$i][$key][$k] = [
217                   '#title'         => isset($item['title']) ? $item['title'] : '',
218                   '#default_value' => isset($options['responsives']['responsive'][$i][$key][$k]) ? $options['responsives']['responsive'][$i][$key][$k] : $item['default'],
219                   '#description'   => isset($item['description']) ? $item['description'] : '',
220                   '#attributes'    => $tooltip,
221                 ];
222
223                 if (isset($item['type'])) {
224                   $form['responsives']['responsive'][$i][$key][$k]['#type'] = $item['type'];
225                 }
226
227                 // Specify proper states for the breakpoint form elements.
228                 if (isset($item['states'])) {
229                   $states = '';
230                   switch ($k) {
231                     case 'pauseOnHover':
232                     case 'pauseOnDotsHover':
233                     case 'autoplaySpeed':
234                       $states = ['visible' => [':input[name*="[' . $i . '][settings][autoplay]"]' => ['checked' => TRUE]]];
235                       break;
236
237                     case 'centerPadding':
238                       $states = ['visible' => [':input[name*="[' . $i . '][settings][centerMode]"]' => ['checked' => TRUE]]];
239                       break;
240
241                     case 'touchThreshold':
242                       $states = ['visible' => [':input[name*="[' . $i . '][settings][touchMove]"]' => ['checked' => TRUE]]];
243                       break;
244
245                     case 'swipeToSlide':
246                       $states = ['visible' => [':input[name*="[' . $i . '][settings][swipe]"]' => ['checked' => TRUE]]];
247                       break;
248
249                     case 'verticalSwiping':
250                       $states = ['visible' => [':input[name*="[' . $i . '][settings][vertical]"]' => ['checked' => TRUE]]];
251                       break;
252                   }
253
254                   if ($states) {
255                     $form['responsives']['responsive'][$i][$key][$k]['#states'] = $states;
256                   }
257                 }
258
259                 if (isset($item['options'])) {
260                   $form['responsives']['responsive'][$i][$key][$k]['#options'] = $item['options'];
261                 }
262
263                 if (isset($item['empty_option'])) {
264                   $form['responsives']['responsive'][$i][$key][$k]['#empty_option'] = $item['empty_option'];
265                 }
266
267                 if (isset($item['field_suffix'])) {
268                   $form['responsives']['responsive'][$i][$key][$k]['#field_suffix'] = $item['field_suffix'];
269                 }
270
271                 if ($admin_css && !isset($item['field_suffix']) && is_bool($item['default'])) {
272                   $form['responsives']['responsive'][$i][$key][$k]['#field_suffix'] = '&nbsp;';
273                   $form['responsives']['responsive'][$i][$key][$k]['#title_display'] = 'before';
274                 }
275               }
276               break;
277
278             default:
279               break;
280           }
281         }
282       }
283     }
284
285     // Attach Slick admin library.
286     if ($admin_css) {
287       $form['#attached']['library'][] = 'slick_ui/slick.admin.vtabs';
288     }
289     return $form;
290   }
291
292   /**
293    * Defines available options for the main and responsive settings.
294    *
295    * @return array
296    *   All available Slick options.
297    *
298    * @see http://kenwheeler.github.io/slick
299    */
300   public function getFormElements() {
301     if (!isset($this->formElements)) {
302       $elements = [];
303
304       $elements['mobileFirst'] = [
305         'type'        => 'checkbox',
306         'title'       => $this->t('Mobile first'),
307         'description' => $this->t('Responsive settings use mobile first calculation, or equivalent to min-width query.'),
308       ];
309
310       $elements['asNavFor'] = [
311         'type'        => 'textfield',
312         'title'       => $this->t('asNavFor target'),
313         'description' => $this->t('Leave empty if using sub-modules to have it auto-matched. Set the slider to be the navigation of other slider (Class or ID Name). Use selector identifier ("." or "#") accordingly. See HTML structure section at README.txt for more info. Overriden by field formatter, or Views style.'),
314       ];
315
316       $elements['accessibility'] = [
317         'type'        => 'checkbox',
318         'title'       => $this->t('Accessibility'),
319         'description' => $this->t('Enables tabbing and arrow key navigation'),
320       ];
321
322       $elements['adaptiveHeight'] = [
323         'type'        => 'checkbox',
324         'title'       => $this->t('Adaptive height'),
325         'description' => $this->t('Enables adaptive height for SINGLE slide horizontal carousels. This is useless with variableWidth.'),
326       ];
327
328       $elements['autoplay'] = [
329         'type'        => 'checkbox',
330         'title'       => $this->t('Autoplay'),
331         'description' => $this->t('Enables autoplay'),
332       ];
333
334       $elements['autoplaySpeed'] = [
335         'type'        => 'textfield',
336         'title'       => $this->t('Autoplay speed'),
337         'description' => $this->t('Autoplay speed in milliseconds'),
338       ];
339
340       $elements['pauseOnHover'] = [
341         'type'        => 'checkbox',
342         'title'       => $this->t('Pause on hover'),
343         'description' => $this->t('Pause autoplay on hover'),
344       ];
345
346       $elements['pauseOnDotsHover'] = [
347         'type'        => 'checkbox',
348         'title'       => $this->t('Pause on dots hover'),
349         'description' => $this->t('Pause autoplay when a dot is hovered.'),
350       ];
351
352       $elements['arrows'] = [
353         'type'        => 'checkbox',
354         'title'       => $this->t('Arrows'),
355         'description' => $this->t('Show prev/next arrows'),
356       ];
357
358       $elements['prevArrow'] = [
359         'type'        => 'textfield',
360         'title'       => $this->t('Previous arrow'),
361         'description' => $this->t("Customize the previous arrow markups. Be sure to keep the expected class: slick-prev."),
362       ];
363
364       $elements['nextArrow'] = [
365         'type'        => 'textfield',
366         'title'       => $this->t('Next arrow'),
367         'description' => $this->t("Customize the next arrow markups. Be sure to keep the expected class: slick-next."),
368       ];
369
370       $elements['downArrow'] = [
371         'type'        => 'checkbox',
372         'title'       => $this->t('Use arrow down'),
373         'description' => $this->t('Arrow down to scroll down into a certain page section. Be sure to provide its target selector.'),
374       ];
375
376       $elements['downArrowTarget'] = [
377         'type'        => 'textfield',
378         'title'       => $this->t('Arrow down target'),
379         'description' => $this->t('Valid CSS selector to scroll to, e.g.: #main, or #content.'),
380       ];
381
382       $elements['downArrowOffset'] = [
383         'type'         => 'textfield',
384         'title'        => $this->t('Arrow down offset'),
385         'description'  => $this->t('Offset when scrolled down from the top.'),
386         'field_suffix' => 'px',
387       ];
388
389       $elements['centerMode'] = [
390         'type'        => 'checkbox',
391         'title'       => $this->t('Center mode'),
392         'description' => $this->t('Enables centered view with partial prev/next slides. Use with odd numbered slidesToShow counts.'),
393       ];
394
395       $elements['centerPadding'] = [
396         'type'        => 'textfield',
397         'title'       => $this->t('Center padding'),
398         'description' => $this->t('Side padding when in center mode (px or %). Be aware, too large padding at small breakpoint will screw the slide calculation with slidesToShow.'),
399       ];
400
401       $elements['dots'] = [
402         'type'        => 'checkbox',
403         'title'       => $this->t('Dots'),
404         'description' => $this->t('Show dot indicators.'),
405       ];
406
407       $elements['dotsClass'] = [
408         'type'        => 'textfield',
409         'title'       => $this->t('Dot class'),
410         'description' => $this->t('Class for slide indicator dots container. Do not prefix with a dot (.). If you change this, edit its CSS accordingly.'),
411       ];
412
413       $elements['appendDots'] = [
414         'type'        => 'textfield',
415         'title'       => $this->t('Append dots'),
416         'description' => $this->t('Change where the navigation dots are attached (Selector, htmlString). If you change this, be sure to provide its relevant markup. Try <strong>.slick__arrow</strong> to achieve this style: <br />&lt; o o o o o o o &gt;<br />Be sure to enable Arrows in such a case.'),
417       ];
418
419       $elements['draggable'] = [
420         'type'        => 'checkbox',
421         'title'       => $this->t('Draggable'),
422         'description' => $this->t('Enable mouse dragging.'),
423       ];
424
425       $elements['fade'] = [
426         'type'        => 'checkbox',
427         'title'       => $this->t('Fade'),
428         'description' => $this->t('Enable fade. Warning! This wants slidesToShow 1. Larger than 1, and Slick may be screwed up.'),
429       ];
430
431       $elements['focusOnSelect'] = [
432         'type'        => 'checkbox',
433         'title'       => $this->t('Focus on select'),
434         'description' => $this->t('Enable focus on selected element (click).'),
435       ];
436
437       $elements['infinite'] = [
438         'type'        => 'checkbox',
439         'title'       => $this->t('Infinite'),
440         'description' => $this->t('Infinite loop sliding.'),
441       ];
442
443       $elements['initialSlide'] = [
444         'type'        => 'number',
445         'title'       => $this->t('Initial slide'),
446         'description' => $this->t('Slide to start on.'),
447       ];
448
449       $elements['lazyLoad'] = [
450         'type'         => 'select',
451         'title'        => $this->t('Lazy load'),
452         'options'      => $this->getLazyloadOptions(),
453         'empty_option' => $this->t('- None -'),
454         'description'  => $this->t("Set lazy loading technique. Ondemand will load the image as soon as you slide to it. Progressive loads one image after the other when the page loads. Anticipated preloads images, and requires Slick 1.6.1+. To share images for Pinterest, leave empty, otherwise no way to read actual image src. It supports Blazy module to delay loading below-fold images until 100px before they are visible at viewport, and/or have a bonus lazyLoadAhead when the beforeChange event fired.", ['@url' => '//www.drupal.org/project/imageinfo_cache']),
455       ];
456
457       $elements['mouseWheel'] = [
458         'type'        => 'checkbox',
459         'title'       => $this->t('Enable mousewheel'),
460         'description' => $this->t('Be sure to download the <a href="@mousewheel" target="_blank">mousewheel</a> library, and it is available at <em>/libraries/mousewheel/jquery.mousewheel.min.js</em>.', ['@mousewheel' => '//github.com/brandonaaron/jquery-mousewheel']),
461       ];
462
463       $elements['randomize'] = [
464         'type'        => 'checkbox',
465         'title'       => $this->t('Randomize'),
466         'description' => $this->t('Randomize the slide display, useful to manipulate cached blocks.'),
467       ];
468
469       $responds = ['window', 'slider', 'min'];
470       $elements['respondTo'] = [
471         'type'        => 'select',
472         'title'       => $this->t('Respond to'),
473         'description' => $this->t("Width that responsive object responds to. Can be 'window', 'slider' or 'min' (the smaller of the two)."),
474         'options'     => array_combine($responds, $responds),
475       ];
476
477       $elements['rtl'] = [
478         'type'        => 'checkbox',
479         'title'       => $this->t('RTL'),
480         'description' => $this->t("Change the slider's direction to become right-to-left."),
481       ];
482
483       $elements['rows'] = [
484         'type'        => 'textfield',
485         'title'       => $this->t('Rows'),
486         'description' => $this->t("Setting this to more than 1 initializes grid mode. Use slidesPerRow to set how many slides should be in each row."),
487       ];
488
489       $elements['slidesPerRow'] = [
490         'type'        => 'textfield',
491         'title'       => $this->t('Slides per row'),
492         'description' => $this->t("With grid mode intialized via the rows option, this sets how many slides are in each grid row."),
493       ];
494
495       $elements['slide'] = [
496         'type'        => 'textfield',
497         'title'       => $this->t('Slide element'),
498         'description' => $this->t("Element query to use as slide. Slick will use any direct children as slides, without having to specify which tag or selector to target."),
499       ];
500
501       $elements['slidesToShow'] = [
502         'type'        => 'number',
503         'title'       => $this->t('Slides to show'),
504         'description' => $this->t('Number of slides to show at a time. If 1, it will behave like slideshow, more than 1 a carousel. Provide more if it is a thumbnail navigation with asNavFor. Only works with odd number slidesToShow counts when using centerMode (e.g.: 3, 5, 7, etc.). Not-compatible with variableWidth.'),
505       ];
506
507       $elements['slidesToScroll'] = [
508         'type'        => 'number',
509         'title'       => $this->t('Slides to scroll'),
510         'description' => $this->t('Number of slides to scroll at a time, or steps at each scroll.'),
511       ];
512
513       $elements['speed'] = [
514         'type'         => 'number',
515         'title'        => $this->t('Speed'),
516         'description'  => $this->t('Slide/Fade animation speed in milliseconds.'),
517         'field_suffix' => 'ms',
518       ];
519
520       $elements['swipe'] = [
521         'type'        => 'checkbox',
522         'title'       => $this->t('Swipe'),
523         'description' => $this->t('Enable swiping.'),
524       ];
525
526       $elements['swipeToSlide'] = [
527         'type'        => 'checkbox',
528         'title'       => $this->t('Swipe to slide'),
529         'description' => $this->t('Allow users to drag or swipe directly to a slide irrespective of slidesToScroll.'),
530       ];
531
532       $elements['edgeFriction'] = [
533         'type'        => 'textfield',
534         'title'       => $this->t('Edge friction'),
535         'description' => $this->t("Resistance when swiping edges of non-infinite carousels. If you don't want resistance, set it to 1."),
536       ];
537
538       $elements['touchMove'] = [
539         'type'        => 'checkbox',
540         'title'       => $this->t('Touch move'),
541         'description' => $this->t('Enable slide motion with touch.'),
542       ];
543
544       $elements['touchThreshold'] = [
545         'type'        => 'number',
546         'title'       => $this->t('Touch threshold'),
547         'description' => $this->t('Swipe distance threshold.'),
548       ];
549
550       $elements['useCSS'] = [
551         'type'        => 'checkbox',
552         'title'       => $this->t('Use CSS'),
553         'description' => $this->t('Enable/disable CSS transitions.'),
554       ];
555
556       $elements['cssEase'] = [
557         'type'        => 'textfield',
558         'title'       => $this->t('CSS ease'),
559         'description' => $this->t('CSS3 animation easing. <a href="@ceaser">Learn</a> <a href="@bezier">more</a>. Ignored if <strong>CSS ease override</strong> is provided.', ['@ceaser' => '//matthewlein.com/ceaser/', '@bezier' => '//cubic-bezier.com']),
560       ];
561
562       $elements['cssEaseBezier'] = [
563         'type'        => 'hidden',
564       ];
565
566       $elements['cssEaseOverride'] = [
567         'title'        => $this->t('CSS ease override'),
568         'type'         => 'select',
569         'options'      => $this->getCssEasingOptions(),
570         'empty_option' => $this->t('- None -'),
571         'description'  => $this->t('If provided, this will override the CSS ease with the pre-defined CSS easings based on <a href="@ceaser">CSS Easing Animation Tool</a>. Leave it empty to use your own CSS ease.', ['@ceaser' => 'http://matthewlein.com/ceaser/']),
572       ];
573
574       $elements['useTransform'] = [
575         'type'        => 'checkbox',
576         'title'       => $this->t('Use CSS Transforms'),
577         'description' => $this->t('Enable/disable CSS transforms.'),
578       ];
579
580       $elements['easing'] = [
581         'title'        => $this->t('jQuery easing'),
582         'type'         => 'select',
583         'options'      => $this->getJsEasingOptions(),
584         'empty_option' => $this->t('- None -'),
585         'description'  => $this->t('Add easing for jQuery animate as fallback. Use with <a href="@easing">easing</a> libraries or default easing methods. Optionally install <a href="@jqeasing">jqeasing module</a>. This will be ignored and replaced by CSS ease for supporting browsers, or effective if useCSS is disabled.', ['@jqeasing' => '//drupal.org/project/jqeasing', '@easing' => '//gsgd.co.uk/sandbox/jquery/easing/']),
586       ];
587
588       $elements['variableWidth'] = [
589         'type'        => 'checkbox',
590         'title'       => $this->t('Variable width'),
591         'description' => $this->t('Disables automatic slide width calculation. Best with uniform image heights, use scale height image effect. Useless with adaptiveHeight, and non-uniform image heights. Useless with slidesToShow > 1 if the container is smaller than the amount of visible slides. Troubled with lazyLoad ondemand.'),
592       ];
593
594       $elements['vertical'] = [
595         'type'        => 'checkbox',
596         'title'       => $this->t('Vertical'),
597         'description' => $this->t('Vertical slide direction. See <a href="@url" target="_blank">relevant issue</a>.', ['@url' => '//github.com/kenwheeler/slick/issues/1001']),
598       ];
599
600       $elements['verticalSwiping'] = [
601         'type'        => 'checkbox',
602         'title'       => $this->t('Vertical swiping'),
603         'description' => $this->t('Changes swipe direction to vertical.'),
604       ];
605
606       $elements['waitForAnimate'] = [
607         'type'        => 'checkbox',
608         'title'       => $this->t('Wait for animate'),
609         'description' => $this->t('Ignores requests to advance the slide while animating.'),
610       ];
611
612       // Defines the default values if available.
613       $defaults = Slick::defaultSettings();
614       foreach ($elements as $name => $element) {
615         $default = $element['type'] == 'checkbox' ? FALSE : '';
616         $elements[$name]['default'] = isset($defaults[$name]) ? $defaults[$name] : $default;
617       }
618
619       foreach (Slick::getDependentOptions() as $parent => $items) {
620         foreach ($items as $name) {
621           if (isset($elements[$name])) {
622             $states = ['visible' => [':input[name*="options[settings][' . $parent . ']"]' => ['checked' => TRUE]]];
623             if (!isset($elements[$name]['states'])) {
624               $elements[$name]['states'] = $states;
625             }
626             else {
627               $elements[$name]['states'] = array_merge($elements[$name]['states'], $states);
628             }
629           }
630         }
631       }
632
633       $this->formElements = $elements;
634     }
635
636     return $this->formElements;
637   }
638
639   /**
640    * Removes problematic options for the responsive Slick.
641    *
642    * The problematic options are those that should exist once for a given Slick
643    *   instance, or no easy way to deal with in the responsive context.
644    *   JS takes care of the relevant copy on each responsive setting instead.
645    *
646    * @return array
647    *   An array of cleaned out options.
648    */
649   public function cleanFormElements() {
650     $excludes = [
651       'accessibility',
652       'appendArrows',
653       'appendDots',
654       'asNavFor',
655       'cssEase',
656       'cssEaseBezier',
657       'cssEaseOverride',
658       'dotsClass',
659       'downArrow',
660       'downArrowTarget',
661       'downArrowOffset',
662       'easing',
663       'lazyLoad',
664       'mobileFirst',
665       'mouseWheel',
666       'nextArrow',
667       'prevArrow',
668       'randomize',
669       'rtl',
670       'slide',
671       'useCSS',
672       'useTransform',
673     ];
674     return array_diff_key($this->getFormElements(), array_combine($excludes, $excludes));
675   }
676
677   /**
678    * Defines available options for the responsive Slick.
679    *
680    * @param int $count
681    *   The number of breakpoints.
682    *
683    * @return array
684    *   An array of Slick responsive options.
685    */
686   public function getResponsiveFormElements($count = 0) {
687     $elements = [];
688     $range = range(0, ($count - 1));
689     $breakpoints = array_combine($range, $range);
690
691     foreach ($breakpoints as $key => $breakpoint) {
692       $elements[$key] = [
693         'type'  => 'details',
694         'title' => $this->t('Breakpoint #@key', ['@key' => ($key + 1)]),
695       ];
696
697       $elements[$key]['breakpoint'] = [
698         'type'         => 'textfield',
699         'title'        => $this->t('Breakpoint'),
700         'description'  => $this->t('Breakpoint width in pixel. If mobileFirst enabled, equivalent to min-width, otherwise max-width.'),
701         'default'      => '',
702         'field_suffix' => 'px',
703       ];
704
705       $elements[$key]['unslick'] = [
706         'type'        => 'checkbox',
707         'title'       => $this->t('Unslick'),
708         'description' => $this->t("Disable Slick at a given breakpoint. Note, you can't window shrink this, once you unslick, you are unslicked."),
709         'default'     => FALSE,
710       ];
711
712       $elements[$key]['settings'] = [
713         'type'  => 'details',
714         'title' => $this->t('Settings'),
715       ];
716
717       // Duplicate relevant main settings.
718       foreach ($this->cleanFormElements() as $name => $responsive) {
719         $elements[$key]['settings'][$name] = $responsive;
720       }
721     }
722     return $elements;
723   }
724
725   /**
726    * Returns modifiable lazyload options.
727    */
728   public function getLazyloadOptions() {
729     $options = [
730       'anticipated' => $this->t('Anticipated'),
731       'blazy'       => $this->t('Blazy'),
732       'ondemand'    => $this->t('On demand'),
733       'progressive' => $this->t('Progressive'),
734     ];
735
736     $this->manager->getModuleHandler()->alter('slick_lazyload_options_info', $options);
737     return $options;
738   }
739
740   /**
741    * {@inheritdoc}
742    */
743   public function validateForm(array &$form, FormStateInterface $form_state) {
744     parent::validateForm($form, $form_state);
745
746     // Update CSS Bezier version.
747     $override = $form_state->getValue(['options', 'settings', 'cssEaseOverride']);
748     if ($override) {
749       $override = $this->getBezier($override);
750     }
751
752     // Update cssEaseBezier value based on cssEaseOverride.
753     $form_state->setValue(['options', 'settings', 'cssEaseBezier'], $override);
754   }
755
756   /**
757    * Overrides Drupal\Core\Entity\EntityFormController::save().
758    */
759   public function save(array $form, FormStateInterface $form_state) {
760     parent::save($form, $form_state);
761
762     $form_state->setRedirectUrl($this->entity->toUrl('collection'));
763   }
764
765 }