' . $build . ''; } return $build; } /** * Prepares variables for slick templates. * * Default template: slick.tpl.php. * * @variables array: * An associative array containing: * - element: An associative array containing the properties of the element. * Properties used: #items, #settings, #options, #optionset, #attached. * - #settings is set via sub-modules and serves various purposes, and not * related to JS settings, mostly slide layouts or attaching assets. * - #options is set programmatically, or hand-crafted, and only accepts * direct key|value pairs related to JS settings, or an optionset name. * - #optionset, if supplied, ensures the optionset loaded once, and cached. */ function template_preprocess_slick(&$variables) { $defaults = array( 'current_display' => 'main', 'optionset' => 'default', 'skin_arrows' => '', ); $element = $variables['element']; $settings = isset($element['#settings']) ? array_merge($defaults, $element['#settings']) : $defaults; $customs = isset($element['#options']) ? $element['#options'] : array(); $name = isset($customs['optionset']) ? strip_tags($customs['optionset']) : $settings['optionset']; $optionset = isset($element['#optionset']) && is_object($element['#optionset']) ? $element['#optionset'] : slick_optionset_load($name); $general = $optionset->options['general']; $goodies = $general['goodies']; $js = $customs ? array_merge($optionset->options['settings'], $customs) : $optionset->options['settings']; $skin = empty($settings['skin']) ? $optionset->skin : $settings['skin']; $display = $settings['current_display']; $id = empty($settings['id']) ? slick_html_id('slick') : $settings['id']; // Allows manipulating markups with an enforced unslick. $settings['count'] = empty($settings['count']) ? count($element['#items']) : $settings['count']; $settings['skin_arrows'] = empty($settings['skin_arrows']) ? '' : ' slick__arrow--' . str_replace('_', '-', $settings['skin_arrows']); $settings['unslick'] = !empty($settings['unslick']) || $settings['count'] == 1; $settings['slidesToShow'] = $js['slidesToShow']; // Prepare attributes, supports Omega 4 alike, or regular. $attributes = &$variables['attributes_array']; $attributes['class'] = isset($attributes['class']) ? $attributes['class'] : array('slick'); $attributes['id'] = $id; $content_attributes = &$variables['content_attributes_array']; if ($display == 'thumbnail') { $attributes['id'] = $id . '-thumbnail'; $skin = empty($settings['skin_thumbnail']) ? $optionset->skin : $settings['skin_thumbnail']; } elseif ($display == 'main') { // Some settings are only reasonable for the main display, not thumbnail. $settings['has_pattern'] = !empty($settings['has_pattern']) || !empty($goodies['pattern']); if (!empty($settings['media_switch']) && strpos($settings['media_switch'], 'box') !== FALSE) { $swicther = str_replace('-switch', '', $settings['media_switch']); $attributes['class'][] = 'slick--' . $swicther; } } // Sniffs for Views to allow block__no_wrapper, views__no_wrapper, etc. if (!empty($settings['view_name']) && !empty($settings['current_view_mode'])) { $attributes['class'][] = str_replace('_', '-', 'slick--view--' . $settings['view_name']); $attributes['class'][] = str_replace('_', '-', 'slick--view--' . $settings['view_name'] . '--' . $settings['current_view_mode']); } // @todo: Remove temp fix for when total <= slidesToShow. // @see https://github.com/kenwheeler/slick/issues/262 if ($settings['count'] <= $settings['slidesToShow']) { $attributes['class'][] = 'slick--less'; } // Consistent styling is always needed even for an unslick. if ($skin) { foreach (array('boxed', 'split') as $key) { if ($skin !== $key && strpos($skin, $key) !== FALSE) { $attributes['class'][] = 'slick--skin--' . $key; } } $attributes['class'][] = str_replace('_', '-', 'slick--skin--' . $skin); $settings['skin'] = $skin; } $attributes['class'][] = str_replace('_', '-', 'slick--optionset--' . $name); if (!empty($general['template_class'])) { $attributes['class'][] = $general['template_class']; } // Prevents broken slick when only one item given, or an enforced unslick. if (!empty($settings['unslick'])) { $attributes['class'][] = 'unslick'; } else { $js['randomize'] = !empty($goodies['random']); $content_attributes['class'][] = 'slick__slider'; $content_attributes['id'] = $attributes['id'] . '-slider'; // The slider must have the attribute "dir" set to "rtl", if so configured. if (!empty($js['rtl'])) { $attributes['dir'] = 'rtl'; } // Arrows are enforced to allow responsive options hide/show them. $tags = ''; } // Add the configuration as JSON object into the slick container. $js_data = _slick_remove_default_optionset_options($optionset, $js, $settings); if (!isset($content_attributes['data-slick']) && $js_data) { $content_attributes['data-slick'] = drupal_json_encode($js_data); } } $variables['settings'] = $settings; // Process individual item. $variables['items'] = array(); foreach ($element['#items'] as $delta => $item) { $settings['current_item'] = $display; $settings = isset($item['settings']) ? array_merge($settings, $item['settings']) : $settings; $slide = array( '#theme' => 'slick_item', '#item' => isset($item['slide']) ? $item['slide'] : $item, '#caption' => empty($item['caption']) ? array() : array_filter($item['caption']), '#delta' => $delta, '#settings' => $settings, ); $variables['items'][$delta] = $slide; unset($slide); } $variables['classes_array'] = $attributes['class']; } /** * Implements hook_preprocess_slick_item(). */ function template_preprocess_slick_item(&$variables) { $element = $variables['element']; $delta = $element['#delta']; $item = $variables['item'] = $element['#item']; $settings = $element['#settings']; $type = isset($item['#item']['type']) ? $item['#item']['type'] : ''; // Prepare variables, and remove non-BEM default class. foreach (array('content', 'item', 'title', 'wrapper') as $key) { $variables[$key . '_prefix'] = $variables[$key . '_suffix'] = ''; } // Configure attributes for containing elements. $attributes['class'] = array('slick__slide', 'slide', 'slide--' . $delta); // Media module has type: image, audio, video, as opposed to field_type. if ($type && $type != 'image') { $attributes['class'][] = 'slide--' . $type; } // All slide types -- main, thumbnail, grid, overlay -- may have captions. $variables['caption'] = $element['#caption']; $variables['slide_pattern'] = ''; // Title, caption and overlay, or nested media. if ($settings['current_item'] != 'thumbnail') { // Each slide can have unique, or uniform layout. if (!empty($settings['layout'])) { $attributes['class'][] = str_replace('_', '-', 'slide--caption--' . $settings['layout']); } // Split image from captions if we do have captions, and main image. if (($variables['caption'] && $item) || (!empty($settings['skin']) && strpos($settings['skin'], '3d') !== FALSE)) { $variables['item_prefix'] = '
'; $variables['item_suffix'] = '
'; } // If fullwidth or fullscreen, add wrappers to hold caption and overlay. if (!empty($settings['skin']) && strpos($settings['skin'], 'full') !== FALSE) { $variables['title_prefix'] = '
'; $variables['title_suffix'] = '
'; } // Exclude lightbox switcher as it has its own pattern DIV within A tag. if (!empty($settings['has_pattern']) && empty($settings['lightbox'])) { $variables['slide_pattern'] = '
'; } // Add helper classes for nested sliders. if (!empty($settings['nested_slick'])) { $attributes['class'][] = $settings['current_item'] == 'overlay' ? 'slide--nested' : 'slide--nester'; } // Custom individual slide classes. if (!empty($settings['slide_classes'])) { $attributes['class'][] = trim($settings['slide_classes']); } } // Do not add divities for a single slick (unslick) to have clean markups. // Or when it is a grid item. if ($settings['current_item'] != 'grid') { $variables['wrapper_prefix'] = ''; $variables['wrapper_suffix'] = ''; } $settings['wrapper'] = $settings['count'] > 1 && $settings['current_item'] != 'grid'; if ($settings['wrapper'] && empty($settings['grid'])) { $variables['content_prefix'] = '
'; $variables['content_suffix'] = '
'; } $variables['settings'] = $settings; } /** * Implements hook_preprocess_slick_grid(). */ function template_preprocess_slick_grid(&$variables) { $element = $variables['element']; $settings = $element['#settings']; $attributes = &$variables['attributes_array']; $attributes = array('class' => array('slick__grid', 'block-grid')); if (empty($settings['unslick'])) { $attributes['class'][] = 'slide__content'; } $settings['grid_large'] = $settings['grid']; foreach (array('small', 'medium', 'large') as $grid) { if ($column = $settings['grid_' . $grid]) { $attributes['class'][] = $grid . '-block-grid-' . $column; } } $variables['items'] = array(); foreach ($element['#items'] as $delta => $item) { $settings['current_item'] = 'grid'; $settings = isset($item['settings']) ? array_merge($settings, $item['settings']) : $settings; $classes = array('slide__grid', 'grid', 'grid--' . $delta); $variables['item_attributes_array'][$delta]['class'] = $classes; $slide['slide'] = array( '#theme' => 'slick_item', '#item' => isset($item['slide']) ? $item['slide'] : $item, '#caption' => empty($item['caption']) ? array() : array_filter($item['caption']), '#delta' => $delta, '#settings' => $settings, ); $variables['items'][$delta] = $slide; unset($slide); } $variables['classes_array'] = $attributes['class']; } /** * Implements hook_process_slick_grid(). */ function template_process_slick_grid(&$variables) { $variables['attributes'] = empty($variables['attributes_array']) ? '' : drupal_attributes($variables['attributes_array']); foreach ($variables['items'] as $delta => $item) { $variables['item_attributes'][$delta] = empty($variables['item_attributes_array'][$delta]) ? '' : drupal_attributes($variables['item_attributes_array'][$delta]); } } /** * Returns HTML for a slick_image. * * @param array $variables * An associative array containing: * - item: Associative array of image data, which may include "uri", "alt", * "width", "height", "title" and "attributes". * - image_style: The name of the style to alter the original image. * - url: A string containing the link 'url'. * - item_attributes: Associative array of attributes to be placed in the img. * - settings: An array of options. * * @ingroup themeable */ function theme_slick_image(array $variables) { $element = $variables['element']; $elements = array( 'captions', 'item', 'item_attributes', 'image_style', 'settings', 'url', 'url_attributes', ); // Faking variables as we don't do preprocess. foreach ($elements as $key) { $variables[$key] = isset($element["#$key"]) ? $element["#$key"] : array(); } // Load the supported formatter variables for the possesive blazy wrapper. $settings = &$variables['settings']; $item = $variables['item']; $image_attributes = &$variables['item_attributes']; $url_attributes = &$variables['url_attributes']; $iframe_attributes = array(); if (isset($settings['content_attributes'])) { $iframe_attributes = &$settings['content_attributes']; } // Modifies variables. foreach (array('icon', 'lightbox', 'media_switch') as $key) { $settings[$key] = isset($settings[$key]) ? $settings[$key] : ''; } $build = ''; $type = empty($item['type']) ? 'image' : $item['type']; $media = !empty($item['embed_url']) && $type != 'image'; $switch = $settings['media_switch']; $uri = $item['uri']; $settings['image_url'] = empty($variables['image_style']) ? file_create_url($uri) : image_style_url($variables['image_style'], $uri); $settings['ratio'] = empty($settings['ratio']) ? '' : str_replace(':', '', $settings['ratio']); // Build attributes. $attributes = array('class' => array('media', 'media--' . $type)); if ($switch) { $attributes['class'][] = 'media--switch'; } foreach (array('width', 'height', 'alt', 'title') as $key) { if (isset($item[$key])) { if (array_key_exists($key, $image_attributes)) { continue; } $image_attributes[$key] = $item[$key]; } } // Picture integration, else Slick lazyload, or regular image. $params = $image_attributes; if (empty($params['breakpoints'])) { $image_attributes['class'][] = 'media__image media__element'; // Aspect ratio to fix layout reflow with lazyloaded images responsively. if (!empty($settings['ratio'])) { $attributes['class'][] = 'media--ratio media--ratio--' . $settings['ratio']; if (!empty($image_attributes['height']) && in_array($settings['ratio'], array('enforced', 'fluid'))) { $attributes['style'] = 'padding-bottom: ' . round((($image_attributes['height'] / $image_attributes['width']) * 100), 2) . '%'; } } if (!empty($settings['background'])) { // @todo Blazy integration with multi-serving bakground images. // slick_build_breakpoint_attributes($attributes, $settings); $attributes['class'][] = 'media--background'; } if (!empty($settings['lazy'])) { $attributes['class'][] = 'media--loading'; // Attach data-attributes to the either DIV or IMG container. $image_attributes['src'] = 'data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7'; slick_build_breakpoint_attributes($image_attributes, $settings); // Do not pass to theme_image() as D7 doesn't support data URI, yet. $build = ''; } else { $params['path'] = $settings['image_url']; $build = theme('image', $params); } } else { $params['uri'] = $uri; $build = theme('picture', $params); } // With CSS background, IMG may be emptied, so add to the container instead. if (!empty($settings['thumbnail_style'])) { $attributes['data-thumb'] = image_style_url($settings['thumbnail_style'], $uri); } // Prepares a media player. // build : If iframe switch disabled, use iframe only, remove image. // player: If no colorbox/photobox, it is an image to iframe switcher. // data- : Gets consistent with colorbox to share JS manipulation. // @todo re-check blazy 'data-src' IFRAME lazyload against blazy.media.js. if ($media) { $build = empty($switch) ? '' : $build; $settings['player'] = empty($settings['lightbox']) && $switch != 'content'; $iframe_attributes['data-media'] = drupal_json_encode(array('type' => $type, 'scheme' => $item['scheme'])); $iframe_attributes['data-lazy'] = $item['embed_url']; $iframe_attributes['src'] = empty($settings['iframe_lazy']) ? $item['embed_url'] : 'about:blank'; $iframe_attributes['class'][] = 'media__iframe media__element'; if ($settings['player']) { $attributes['class'][] = 'media--player'; $build .= ''; $build .= ''; $build .= ''; } } $build .= $settings['icon']; $build = '' . $build . ''; // The link to content or lightboxes. if (!empty($variables['url'])) { if (!empty($settings['lightbox'])) { $lightbox = TRUE; $icon = ''; $build .= empty($settings['icon']) ? $icon : $settings['icon']; if (!empty($settings['has_pattern'])) { $build .= '
'; } } $link_options = empty($url_attributes) ? array() : array('attributes' => $url_attributes); $link_options['html'] = TRUE; $build = l($build, $variables['url'], $link_options); if (isset($lightbox) && !empty($variables['captions']['lightbox'])) { $build .= '
' . $variables['captions']['lightbox'] . '
'; } } return $build; } /** * Provides re-usable breakpoint data-attributes. */ function slick_build_breakpoint_attributes(array &$attributes = array(), $settings = array()) { // Blazy can lazyload a single image, Slick not, yet, here comes the trouble. if (!empty($settings['blazy'])) { $settings['lazy_attribute'] = 'src'; $settings['lazy_class'] = 'b-lazy'; } $lazy_class = empty($settings['lazy_class']) ? 'lazy' : $settings['lazy_class']; $lazy_attribute = empty($settings['lazy_attribute']) ? 'lazy' : $settings['lazy_attribute']; // Defines attributes, builtin, or supported lazyload such as Slick. $attributes['class'][] = $lazy_class; $attributes['data-' . $lazy_attribute] = $settings['image_url']; // @todo Blazy integration. if (!empty($settings['breakpoints'])) { if (!empty($settings['background'])) { foreach ($settings['breakpoints'] as $key => $breakpoint) { if (!empty($breakpoint['url'])) { $attributes['data-src-' . $key] = $breakpoint['url']; } } } elseif (!empty($settings['srcset'])) { $attributes['srcset'] = ''; $attributes['data-srcset'] = $settings['srcset']; $attributes['sizes'] = '100w'; if (!empty($settings['sizes'])) { $attributes['sizes'] = trim($settings['sizes']); unset($attributes['width']); unset($attributes['height']); } } } } /** * Strips out options similar to default values from the optionset options. */ function _slick_remove_default_optionset_options($optionset, $js = array(), $context = array()) { $config = array(); $options = $optionset->options; $defaults = slick_get_options(); // Remove wasted dependent options if disabled, empty or not. slick_remove_wasted_dependent_options($js); $config = array_diff_assoc($js, $defaults); if (empty($config['lazyLoad'])) { unset($config['lazyLoad']); } unset($config['prevArrow'], $config['nextArrow']); // Clean up responsive options if similar to the defaults. $responses = array(); if (isset($options['responsives']) && isset($options['responsives']['responsive'])) { $responsives = $options['responsives']['responsive']; foreach ($responsives as $key => $responsive) { if (empty($responsives[$key]['breakpoint'])) { unset($responsives[$key]); } if (isset($responsives[$key])) { $responses[$key] = $responsive; } } if ($responses) { $cleaned = array(); foreach ($responses as $i => $response) { $cleaned[$i]['breakpoint'] = $responses[$i]['breakpoint']; if (isset($responses[$i]['unslick']) && $responses[$i]['unslick']) { $cleaned[$i]['settings'] = 'unslick'; unset($responses[$i]['unslick']); } else { slick_remove_wasted_dependent_options($responses[$i]['settings']); $cleaned[$i]['settings'] = array_diff_assoc($responses[$i]['settings'], $defaults); } } $config['responsive'] = $cleaned; } } return $config; } /** * Removes wasted dependent options, even if not empty. */ function slick_remove_wasted_dependent_options(array &$config = array()) { $options = array( 'autoplay' => array('pauseOnHover', 'pauseOnDotsHover', 'autoplaySpeed'), 'centerMode' => array('centerPadding'), 'dots' => array('dotsClass', 'appendDots'), 'rows' => array('slidesPerRow'), 'swipe' => array('swipeToSlide'), 'vertical' => array('verticalSwiping'), 'useCSS' => array('cssEase', 'cssEaseBezier', 'cssEaseOverride'), ); foreach ($options as $key => $option) { if (isset($config[$key]) && empty($config[$key])) { foreach ($option as $dependent) { unset($config[$dependent]); } } } if (!empty($config['useCSS']) && !empty($config['cssEaseBezier'])) { $config['cssEase'] = $config['cssEaseBezier']; } unset($config['cssEaseOverride'], $config['cssEaseBezier']); }