3 namespace Drupal\slick\Form;
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\Form\BlazyAdminInterface;
11 use Drupal\slick\SlickManagerInterface;
14 * Provides resusable admin functions, or form elements.
16 class SlickAdmin implements SlickAdminInterface {
18 use StringTranslationTrait;
21 * The blazy admin service.
23 * @var \Drupal\blazy\Form\BlazyAdminInterface
25 protected $blazyAdmin;
28 * The slick manager service.
30 * @var \Drupal\slick\SlickManagerInterface
35 * Constructs a SlickAdmin object.
37 * @param \Drupal\blazy\Form\BlazyAdminInterface $blazy_admin
38 * The blazy admin service.
39 * @param \Drupal\slick\SlickManagerInterface $manager
40 * The slick manager service.
42 public function __construct(BlazyAdminInterface $blazy_admin, SlickManagerInterface $manager) {
43 $this->blazyAdmin = $blazy_admin;
44 $this->manager = $manager;
50 public static function create(ContainerInterface $container) {
52 $container->get('blazy.admin.extended'),
53 $container->get('slick.manager')
58 * Returns the blazy admin formatter.
60 public function blazyAdmin() {
61 return $this->blazyAdmin;
65 * Returns the slick manager.
67 public function manager() {
68 return $this->manager;
72 * Returns the main form elements.
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;
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];
88 if (empty($definition['no_layouts'])) {
89 $definition['layouts'] = isset($definition['layouts']) ? array_merge($this->getLayoutOptions(), $definition['layouts']) : $this->getLayoutOptions();
92 $this->openingForm($form, $definition);
94 if (!empty($definition['image_style_form']) && !isset($form['image_style'])) {
95 $this->imageStyleForm($form, $definition);
98 if (!empty($definition['media_switch_form']) && !isset($form['media_switch'])) {
99 $this->mediaSwitchForm($form, $definition);
102 if (!empty($definition['grid_form']) && !isset($form['grid'])) {
103 $this->gridForm($form, $definition);
106 if (!empty($definition['fieldable_form']) && !isset($form['image'])) {
107 $this->fieldableForm($form, $definition);
110 if (!empty($definition['breakpoints'])) {
111 $this->blazyAdmin->breakpointsForm($form, $definition);
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.');
118 $this->closingForm($form, $definition);
122 * Returns the opening form elements.
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');
131 if (!isset($form['optionset'])) {
132 $this->blazyAdmin->openingForm($form, $definition);
134 $form['optionset']['#title'] = $this->t('Optionset main');
137 if (!empty($definition['nav']) || !empty($definition['thumbnails'])) {
138 $form['optionset_thumbnail'] = [
140 '#title' => $this->t('Optionset thumbnail'),
141 '#options' => $this->getOptionsetsByGroupOptions('thumbnail'),
142 '#description' => $this->t('If provided, asNavFor aka thumbnail navigation applies. Leave empty to not use thumbnail navigation.'),
146 $form['skin_thumbnail'] = [
148 '#title' => $this->t('Skin thumbnail'),
149 '#options' => $this->getSkinsByGroupOptions('thumbnail'),
150 '#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]),
155 if (count($arrows) > 0) {
156 $form['skin_arrows'] = [
158 '#title' => $this->t('Skin arrows'),
159 '#options' => $arrows ?: [],
161 '#description' => $this->t('Implement \Drupal\slick\SlickSkinInterface::arrows() to add your own arrows skins, in the same format as SlickSkinInterface::skins().'),
166 if (count($dots) > 0) {
167 $form['skin_dots'] = [
169 '#title' => $this->t('Skin dots'),
170 '#options' => $dots ?: [],
172 '#description' => $this->t('Implement \Drupal\slick\SlickSkinInterface::dots() to add your own dots skins, in the same format as SlickSkinInterface::skins().'),
177 if (!empty($definition['thumb_positions'])) {
178 $form['thumbnail_position'] = [
180 '#title' => $this->t('Thumbnail position'),
182 'left' => $this->t('Left'),
183 'right' => $this->t('Right'),
184 'top' => $this->t('Top'),
185 'over-left' => $this->t('Overlay left'),
186 'over-right' => $this->t('Overlay right'),
187 'over-top' => $this->t('Overlay top'),
189 '#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.'),
192 'select[name*="[optionset_thumbnail]"]' => ['!value' => ''],
199 if (!empty($definition['thumb_captions'])) {
200 $form['thumbnail_caption'] = [
202 '#title' => $this->t('Thumbnail caption'),
203 '#options' => $definition['thumb_captions'],
204 '#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.'),
207 'select[name*="[optionset_thumbnail]"]' => ['!value' => ''],
214 if (isset($form['skin'])) {
215 $form['skin']['#title'] = $this->t('Skin main');
216 $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]);
219 if (isset($form['layout'])) {
220 $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]);
224 foreach (Element::children($form) as $key) {
225 if (!isset($form[$key]['#weight'])) {
226 $form[$key]['#weight'] = ++$weight;
232 * Returns the image formatter form elements.
234 public function mediaSwitchForm(array &$form, $definition = []) {
235 $this->blazyAdmin->mediaSwitchForm($form, $definition);
237 if (isset($form['media_switch'])) {
238 $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>');
240 if (!empty($definition['multimedia']) && isset($definition['fieldable_form'])) {
241 $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>');
244 $form['media_switch']['#description'] .= ' ' . $this->t('</ol> Try selecting "<strong>- None -</strong>" first before changing if trouble with this complex form states.');
247 if (isset($form['ratio']['#description'])) {
248 $form['ratio']['#description'] .= ' ' . $this->t('Required if using media entity to switch between iframe and overlay image, otherwise DIY.');
253 * Returns the image formatter form elements.
255 public function imageStyleForm(array &$form, $definition = []) {
256 $definition['thumbnail_style'] = isset($definition['thumbnail_style']) ? $definition['thumbnail_style'] : TRUE;
257 $definition['ratios'] = isset($definition['ratios']) ? $definition['ratios'] : TRUE;
259 $definition['thumbnail_effect'] = [
260 'hover' => $this->t('Hoverable'),
261 'grid' => $this->t('Static grid'),
264 if (!isset($form['image_style'])) {
265 $this->blazyAdmin->imageStyleForm($form, $definition);
267 $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.');
270 if (isset($form['thumbnail_style'])) {
271 $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.');
274 if (isset($form['thumbnail_effect'])) {
275 $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.');
278 if (isset($form['background'])) {
279 $form['background']['#description'] .= ' ' . $this->t('Works best with a single visible slide, skins full width/screen.');
284 * Returns re-usable fieldable formatter form elements.
286 public function fieldableForm(array &$form, $definition = []) {
287 $this->blazyAdmin->fieldableForm($form, $definition);
289 if (isset($form['thumbnail'])) {
290 $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.");
293 if (isset($form['overlay'])) {
294 $form['overlay']['#title'] = $this->t('Overlay media/slicks');
295 $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.');
300 * Returns re-usable grid elements across Slick field formatter and Views.
302 public function gridForm(array &$form, $definition = []) {
303 if (!isset($form['grid'])) {
304 $this->blazyAdmin->gridForm($form, $definition);
307 $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 > <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>');
309 $form['grid_header']['#markup'] = '<h3 class="form__title form__title--grid">' . $header . '</h3>';
311 $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.');
315 * Returns the closing ending form elements.
317 public function closingForm(array &$form, $definition = []) {
318 $form['override'] = [
319 '#title' => $this->t('Override main optionset'),
320 '#type' => 'checkbox',
321 '#description' => $this->t('If checked, the following options will override the main optionset. Useful to re-use one optionset for several different displays.'),
326 $form['overridables'] = [
327 '#type' => 'checkboxes',
328 '#title' => $this->t('Overridable options'),
329 '#description' => $this->t("Override the main optionset to re-use one. Anything dictated here will override the current main optionset. Unchecked means FALSE"),
330 '#options' => $this->getOverridableOptions(),
335 ':input[name$="[override]"]' => ['checked' => TRUE],
340 $this->blazyAdmin->closingForm($form, $definition);
344 * Returns overridable options to re-use one optionset.
346 public function getOverridableOptions() {
348 'arrows' => $this->t('Arrows'),
349 'autoplay' => $this->t('Autoplay'),
350 'dots' => $this->t('Dots'),
351 'draggable' => $this->t('Draggable'),
352 'infinite' => $this->t('Infinite'),
353 'mouseWheel' => $this->t('Mousewheel'),
354 'randomize' => $this->t('Randomize'),
355 'variableWidth' => $this->t('Variable width'),
358 $this->manager->getModuleHandler()->alter('slick_overridable_options_info', $options);
363 * Returns default layout options for the core Image, or Views.
365 public function getLayoutOptions() {
367 'bottom' => $this->t('Caption bottom'),
368 'top' => $this->t('Caption top'),
369 'right' => $this->t('Caption right'),
370 'left' => $this->t('Caption left'),
371 'center' => $this->t('Caption center'),
372 'center-top' => $this->t('Caption center top'),
373 'below' => $this->t('Caption below the slide'),
374 'stage-right' => $this->t('Caption left, stage right'),
375 'stage-left' => $this->t('Caption right, stage left'),
376 'split-right' => $this->t('Caption left, stage right, split half'),
377 'split-left' => $this->t('Caption right, stage left, split half'),
378 'stage-zebra' => $this->t('Stage zebra'),
379 'split-zebra' => $this->t('Split half zebra'),
384 * Returns available slick optionsets by group.
386 public function getOptionsetsByGroupOptions($group = '') {
387 $optionsets = $groups = $ungroups = [];
388 $slicks = $this->manager->entityLoadMultiple('slick');
389 foreach ($slicks as $slick) {
390 $name = Html::escape($slick->label());
392 $current_group = $slick->getGroup();
393 if (!empty($group)) {
394 if ($current_group) {
395 if ($current_group != $group) {
398 $groups[$id] = $name;
401 $ungroups[$id] = $name;
404 $optionsets[$id] = $name;
407 return $group ? array_merge($ungroups, $groups) : $optionsets;
411 * Returns available slick skins for select options.
413 public function getSkinsByGroupOptions($group = '') {
414 return $this->manager->getSkinsByGroup($group, TRUE);
418 * Return the field formatter settings summary.
420 public function settingsSummary($plugin, $definition = []) {
421 return $this->blazyAdmin->settingsSummary($plugin, $definition);
425 * Returns available fields for select options.
427 public function getFieldOptions($target_bundles = [], $allowed_field_types = [], $entity_type_id = 'media', $target_type = '') {
428 return $this->blazyAdmin->getFieldOptions($target_bundles, $allowed_field_types, $entity_type_id, $target_type);
432 * Returns re-usable logic, styling and assets across fields and Views.
434 public function finalizeForm(array &$form, $definition = []) {
435 return $this->blazyAdmin->finalizeForm($form, $definition);