Kentico Content Slider With Cropped Thumbnails

I had a need to build a content slideshow with thumbnail pagination. In this project, Kentico is our CMS of choice.

In the existing website, users can upload images of any-size and aspect-ratio, and then we resize the image in the Transformation. Our pager thumbnails need to be square; a string of mixed-size images doesn’t look quite right. But unfortunately Kentico doesn’t provide a way to crop images on the fly. Luckily, CSS can help.

Carousel HTML Wrapper

Here is the basic carousel wrapper with a blank UL pager to get things started:

Carousel HTML Wrapper
1
2
3
4
5
6
7
<div class="grid_content featured carousel-wrapper">
     <div class="carousel">
          <!-- content repeater generating our slides. Uses the transformation below -->
     </div>
     <ul id="pager" class="plain"></ul>
     <div class="clear"></div>
</div>

CSS

Our pager is an unordered list with a link and a span. The link has the pagination action attached so it. The span has a fixed size of 50x50—this is desired size of our thumbnails. The thumbnail image is set as the background of the span, centered, then the span will crop off the rest of the image. We now have square thumbnails.

Thumbnail Style
1
2
3
4
5
6
.carousel~#pager li                 {float:left !important; margin:0 20px 0 0; overflow:hidden; }
.carousel~#pager a                  {padding:3px; border:1px solid #ccc;}
.carousel~#pager a .thumbnail       {background-position:50% 50%; background-repeat:no-repeat;}
.carousel~#pager a,
.carousel~#pager a .thumbnail       {width:50px; height:50px; display:block;}
.carousel~#pager li.activeSlide a  {background:#fff;}

Kentico Transformations

The thumbnail() function is responsible for creating our ‘cropped’ thumbnail for the carousel pager. This is actually really simple—just grab the image use a maxSideSide of 50. The CSS above takes care of the ‘cropping’.

We’re using the BlogPostTeaser image object for testing, even though we only need the image URL. It turns out Kentico’s IfEmpty() function isn’t all that reliable, and often <%# IfEmpty ("BlogPostTeaser", "", GetFileURL("BlogPostTeaser")) %> will result in /getattachment/00000000-0000-0000-0000-000000000000/Post-Title.aspx (the URL of a non-existent image).

Kentico’s CMSAbstractTransformation.Eval() function returns an object, while CMSAbstractTransformation.GetFileURL() returns a string. Our function parameters must be declared accordingly and converted for comparison.

The carousel JavaScript generates the pagination HTML, so we’re just storing the thumbnail path in the summary so our JavaScript and pick it up when needed.

Kentico Transformation
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
<script runat="server">
    public static string videoTest(object BlogPostTeaser, string BlogPostTeaserURL, object BlogPostTeaserAltText, object BlogPostVideo)
    {
      ...
    }

    public static string thumbnail(object BlogPostTeaser, string BlogPostTeaserURL)
    {
        //Check the image object to see if it's an actual image or not. 
        //If no image, default to the 'standard' thumb.
        string teaser = Convert.ToString(BlogPostTeaser);
        if (teaser != "")
        {
            return BlogPostTeaserURL + "?height=50";

        }
        else
        {
            return "/App_Themes/coj/images/coj-thumb.png";
        }
    }
</script>

<div class="carouselTransformation">
    <%# videoTest(Eval("BlogPostTeaser"), GetFileUrl("BlogPostTeaser"), Eval("BlogPostVideo"), Eval("BlogPostVideo"))%>
    <div class="title">
        <a href="<%# GetDocumentUrl() %>">
            <%#Eval("BlogPostTitle")%>
        </a>
    </div>
    <div class="date">
        <%#GetDateTime("BlogPostDate", "MMMM dd, yyyy")%>
    </div>
    <div class="summary" thumbnail="<%# thumbnail(Eval("BlogPostTeaser"), GetFileUrl("BlogPostTeaser")) %>">
        <%# LimitLength(Eval("BlogPostSummary"),350,"...") %>
    </div>
</div>

Javascript

The carousel is built on the Cycle jQuery plugin. The pagination is generated by a callback function in the carousel function. In this function we grab the thumbnail URL and generate the pager LI and set the thumbnail as the background of the span. Our CSS above takes care of the rest.

Carousel
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
$(document).ready(function() {

    jQuery.dom = jQuery(document);

    var $carousel = jQuery.dom.find('.carousel');
    if ($carousel.length) {

          $carousel.cycle({
            fx: 'fade',
            speed: 300,
            timeout: 10000,
            pager: '#pager',
            pause: 1,
            cleartypeNoBg: true,

            // A callback function that creates a thumbnail to use as pager anchor
            pagerAnchorBuilder: function(idx, slide) {

              /*     Find your image inside the individual slide.
                 In this case, I generate a scaled image on the server and store the path in an attribute */
              var slideImg = jQuery(slide).children(".summary").attr('thumbnail');
      
              /*  If there is no image associated with the story, use a standard thumbnail
                 This is also handled in our Kentico Transformation, so this is only a backup */
              if (slideImg == undefined) {
                  slideImg = "/App_Themes/site/images/thumb.png";
              };

                /*   Our thumbnails are 50x50, but our image might not be square.
                 Setting the image as the background lets the element crop the image */
                return '<li><a href="#"><span class="thumbnail" style="background-image:url('+ slideImg +');"></span></a></li>';
            }
        });
     });
});

UPDATE The project is now live, so you can take a look at the thumbnails in action: Jacksonville’s Mayor’s new blog