<?php
/**
* @file
* Contains \Drupal\mymodule\Plugin\Field\FieldFormatter\SlickMyentityGalleryFormatter.
*/
namespace Drupal\mymodule\Plugin\Field\FieldFormatter;
use Drupal\Core\Field\FormatterBase;
use Drupal\Core\Field\FieldItemListInterface;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Component\Utility\Html;
/**
* @FieldFormatter(
* id = "slick_myentity_gallery",
* label = @Translation("Slick Myentity Gallery"),
* field_types = {
* "image"
* }
* )
*/
class SlickMyentityGalleryFormatter extends FormatterBase {
/**
* {@inheritdoc}
*/
public static function defaultSettings() {
return [
'visible_slides' => 3,
'image_style' => 'thumbnail',
'arrows' => TRUE,
'dots' => TRUE,
'fade' => FALSE,
'standalone_image' => TRUE,
'standalone_location' => 'above',
'standalone_style' => 'xlarge',
'vertical' => FALSE,
'lazy_load' => 'ondemand',
'hide_single_navigator' => TRUE
] + parent::defaultSettings();
}
/**
* {@inheritdoc}
*/
public function settingsForm(array $form, FormStateInterface $form_state) {
$element = parent::settingsForm($form, $form_state);
$field_name = $this->fieldDefinition->getName();
$image_style_entities = \Drupal::entityManager()
->getStorage('image_style')
->loadMultiple();
$image_styles = array_map(function($image_style) {
return $image_style->label();
}, $image_style_entities);
$image_styles = ['_original' => '- ' . $this->t('Original') . ' -'] + $image_styles;
$element['visible_slides'] = [
'#type' => 'number',
'#title' => $this->t('Number of visible slides'),
'#default_value' => $this->getSetting('visible_slides'),
'#min' => 1,
'#max' => 10,
'#description' => $this->t('Number of images visible at once.')
];
$element['image_style'] = [
'#type' => 'select',
'#title' => $this->t('Image style'),
'#default_value' => $this->getSetting('image_style'),
'#options' => $image_styles,
'#description' => $this->t('Image style to display the images with.')
];
$element['arrows'] = [
'#type' => 'checkbox',
'#title' => $this->t('Show arrows'),
'#default_value' => $this->getSetting('arrows'),
'#description' => $this->t('Display the navigation arrows.')
];
$element['dots'] = [
'#type' => 'checkbox',
'#title' => $this->t('Paging'),
'#default_value' => $this->getSetting('dots'),
'#description' => $this->t('Display the paging dots.')
];
$element['fade'] = [
'#type' => 'checkbox',
'#title' => $this->t('Fade'),
'#default_value' => $this->getSetting('fade'),
'#description' => $this->t('Fade between transitions.')
];
$element['vertical'] = [
'#type' => 'checkbox',
'#title' => $this->t('Vertical slider'),
'#default_value' => $this->getSetting('vertical'),
'#description' => $this->t('Display slider vertically instead of horizontally.')
];
$element['lazy_load'] = [
'#type' => 'select',
'#title' => $this->t('Lazy load'),
'#options' => [
'none' => '- ' . $this->t('None') . ' -',
'ondemand' => $this->t('On demand'),
'progressive' => $this->t('Progressive')
],
'#default_value' => $this->getSetting('lazy_load'),
'#description' => $this->t('Lazy load the images to increase page performance.')
];
$element['standalone_image'] = [
'#type' => 'checkbox',
'#title' => $this->t('Standalone active image'),
'#default_value' => $this->getSetting('standalone_image'),
'#description' => $this->t('Display the active image separately.')
];
$element['standalone_style'] = [
'#type' => 'select',
'#title' => $this->t('Standalone image style'),
'#default_value' => $this->getSetting('standalone_style'),
'#options' => $image_styles,
'#description' => $this->t('Image style to display the standalone image with.'),
'#states' => [
'visible' => [
"input[name=\"fields[$field_name][settings_edit_form][settings][standalone_image]\"]" => [
'checked' => TRUE
]
]
]
];
$element['standalone_location'] = [
'#type' => 'select',
'#title' => $this->t('Standalone image location'),
'#default_value' => $this->getSetting('standalone_location'),
'#options' => [
'above' => $this->t('Above'),
'below' => $this->t('Below'),
'left' => $this->t('Left'),
'right' => $this->t('Right')
],
'#description' => $this->t('Display slider vertically instead of horizontally.'),
'#states' => [
'visible' => [
"input[name=\"fields[$field_name][settings_edit_form][settings][standalone_image]\"]" => [
'checked' => TRUE
]
]
]
];
$element['hide_single_navigator'] = [
'#type' => 'checkbox',
'#title' => $this->t('Hide single item carousel'),
'#default_value' => $this->getSetting('hide_single_navigator'),
'#description' => $this->t('If standalone image is displayed and there is only one image, the carousel will be hidden.'),
'#states' => [
'visible' => [
"input[name=\"fields[$field_name][settings_edit_form][settings][standalone_image]\"]" => [
'checked' => TRUE
]
]
]
];
return $element;
}
/**
* {@inheritdoc}
*/
public function settingsSummary() {
$summary = parent::settingsSummary();
if ($this->getSetting('standalone_image')) {
$standalone_style = $this->getSetting('standalone_style');
if ($standalone_style == '_original') {
$summary[] = $this->t('Display standalone image without image style.');
} else {
$style = \Drupal::entityManager()->getStorage('image_style')->load($standalone_style);
$summary[] = $this->t('Display standalone image with %style image style.', [
'%style' => $style ? $style->label() : 'original'
]);
}
$location = $this->getSetting('standalone_location');
$location_labels = [
'above' => $this->t('above'),
'below' => $this->t('below'),
'left' => $this->t('left'),
'right' => $this->t('right')
];
$summary[] = $this->t('Standalone image position: %position.', [
'%position' => $location_labels[$location]
]);
if ($this->getSetting('hide_single_navigator')) {
$summary[] = $this->t('Hide carousel with single image.');
}
}
$image_style = $this->getSetting('image_style');
if ($image_style == '_original') {
$summary[] = $this->t('Display images without image style.');
} else {
$style = \Drupal::entityManager()->getStorage('image_style')->load($image_style);
$summary[] = $this->t('Display images with %style image style.', [
'%style' => $style ? $style->label() : 'original'
]);
}
if ($this->getSetting('vertical')) {
$summary[] = $this->t('Display slider vertically.');
}
switch ($this->getSetting('lazy_load')) {
case 'ondemand': $summary[] = $this->t('Use <em>on demand</em> lazy loading.'); break;
case 'progressive': $summary[] = $this->t('Use <em>progressive</em> lazy loading.'); break;
}
return $summary;
}
/**
* {@inheritdoc}
*/
public function viewElements(FieldItemListInterface $items, $langcode) {
// Skip if there are no items to display.
if ($items->isEmpty()) {
return [];
}
$standalone_html_id = Html::getUniqueId($items->getName() . '-standalone');
$carousel_id = Html::getUniqueId($items->getName() . '-nav');
$lazy_load = $this->getSetting('lazy_load');
$use_lazy_load = $lazy_load != 'none';
// Retrieve file IDs.
$fids = [];
foreach ($items->getIterator() AS $item) {
$fids[] = $item->get('target_id')->getValue();
}
// Load files so we can get their URIs.
$files = \Drupal::entityManager()->getStorage('file')->loadMultiple($fids);
// Make a list of all URIs.
$uris = array_map(function($file) {
return $file->getFileUri();
}, $files);
// Set up the render element.
$element = [
'#attached' => [
'library' => [
'mymodule/slick_myentity_gallery'
]
]
];
// Create carousel for the standalone image if needed.
if ($this->getSetting('standalone_image')) {
$element['#attributes']['class'][] = 'with-standalone';
$element['standalone'] = [
'#theme' => 'item_list',
'#items' => [],
'#weight' => 0,
'#attributes' => [
'id' => $standalone_html_id,
'class' => [
'slick-myentity-gallery',
'slider-standalone',
'location-' . $this->getSetting('standalone_location')
],
'data-slick-settings' => json_encode([
'slidesToShow' => 1,
'slidesToScroll' => 1,
'arrows' => FALSE,
'fade' => TRUE,
'asNavFor' => '#' . $carousel_id,
'lazyLoad' => $lazy_load,
'mobileFirst' => TRUE
])
]
];
foreach ($uris AS $uri) {
$element['standalone']['#items'][] = $this->getImageItem($uri, $this->getSetting('standalone_style'), $use_lazy_load);
}
}
// Create the main image carousel.
$element['carousel'] = [
'#theme' => 'item_list',
'#items' => [],
'#weight' => 1,
'#attributes' => [
'id' => $carousel_id,
'class' => [
'slick-myentity-gallery',
'slider-navigation',
$this->getSetting('vertical') ? 'vertical' : 'horizontal'
],
'data-slick-settings' => json_encode([
'slidesToShow' => (int) $this->getSetting('visible_slides'),
'slidesToScroll' => 1,
'asNavFor' => '#' . $standalone_html_id,
'dots' => (bool) $this->getSetting('dots'),
'arrows' => (bool) $this->getSetting('arrows'),
'fade' => (bool) $this->getSetting('fade'),
'vertical' => (bool) $this->getSetting('vertical'),
'verticalSwiping' => (bool) $this->getSetting('vertical'),
'focusOnSelect' => TRUE,
'lazyLoad' => $lazy_load,
'mobileFirst' => TRUE,
'rtl' => \Drupal::languageManager()->getCurrentLanguage()->getDirection() == 'rtl',
'infinite' => FALSE
])
]
];
foreach ($uris AS $uri) {
$element['carousel']['#items'][] = $this->getImageItem($uri, $this->getSetting('image_style'), $use_lazy_load);
}
// Display the carouse first if the standalone image is visible and
// is positioned below the carousel or to the right next to it.
if ($this->getSetting('standalone_image') && in_array($this->getSetting('standalone_location'), ['below', 'right'])) {
$element['carousel']['#weight'] = -1;
}
// Hide navigator if standalone image is displayed and there is only
// one image.
if ($this->getSetting('standalone_image') && $this->getSetting('hide_single_navigator') && $items->count() == 1) {
unset($element['carousel']);
}
return [$element];
}
/**
* Helper method to generate image for provided style
* that takes the lazy load setting into account.
*
* @param string $uri
* The original image uri.
* @param string $image_style
* The image style name.
* @param bool $lazy_load
* If TRUE the lazy slick load image will be returned.
*
* @return array
* Renderable array for a single image.
*/
function getImageItem($uri, $image_style, $lazy_load = FALSE) {
if ($lazy_load) {
$style = \Drupal::entityManager()
->getStorage('image_style')
->load($image_style);
return [
'#type' => 'inline_template',
'#template' => '<img data-lazy="{{ path }}" />',
'#context' => [
'path' => $style ? $style->buildUrl($uri) : file_create_url($uri)
]
];
} else {
return [
'#theme' => 'image_style',
'#uri' => $uri,
'#style_name' => $image_style
];
}
}
}
(function($) {
Drupal.behaviors.slickMyentityGallery = {
attach: function(context) {
// Initialize the Slick Carousel on all appropriate elements.
$('.slick-myentity-gallery[data-slick-settings]', context).once('slick-myentity-gallery-init').each(function() {
var $this = $(this);
var settings = $this.data('slick-settings');
// Adjust behavior if this is a Field API field.
var $fapi_items = $this.find('.field__item');
if ($fapi_items.length != 0) {
$fapi_items.parent().slick( settings );
} else {
$this.slick( settings );
}
});
}
}
})(jQuery);