Sharepoint rotating banner with custom pagination control using font awesome

Hello folks, for my current project on SharePoint 2013, I had to develop a rotating banner custom web part using sharepoint REST API service. I had to overwrite the default pagination control CSS as well as the Flex Slider 2 JS plugin to achieve that result as Shown Below.1

So I am gonna show you how I achieved that.
First I downloaded the Flex Slider 2 plugin from http://flexslider.woothemes.com/
Then open Visual Studio 2013 and add a Visual Web part like the below instruction2
Put your site URL and click validate, if the site is correct, than it will show you a successful message.3
Now we will create a Layout Folder for storing our Flex Slider 2 Style Sheets and JavaScript Library. We will use cdn for Font Awesome.
4
Now I have put the Style Sheet and JavaScript in the Layout Folder like below.
5
So we are all set with our development Environment. Now we need to create a Picture Library / Document Library in SharePoint 2013.I have created a picture library called “Home Page Banner” and added some columns.Here is the document library.
6
If we want to upload a new picture just click on new document button and a pop up will open, select a picture and than it will offer us to fill the fields shown as below:
7

Now fill all the field in the dialog box. You see there are a lot of columns there. I had to develop this because client wanted to configure the banner’s property from the Picture Library.

The web part fulfills the following tasks
1. Enable or disable a Banner.
2. Banners are sortable.
3. Change any Text/Color of a banner image.
4. Change Banner Navigation Control using Font Awesome icon Class.
5. Banner Images are clickable.
Now let’s start the coding to fulfill the requirements. First of all let’s add the reference of style sheet file and JS file in the web part. We also add the basic skeleton of the flex Slider 2.
3

I used SharePoint 2013 REST API to pull the data from the Picture Library “Home Page Banner”. For pulling the required data from Share Point list I wrote some code as given below.

<%@ Assembly Name="$SharePoint.Project.AssemblyFullName$" %>
<%@ Assembly Name="Microsoft.Web.CommandUI, Version=15.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>
<%@ Register TagPrefix="SharePoint" Namespace="Microsoft.SharePoint.WebControls" Assembly="Microsoft.SharePoint, Version=15.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>
<%@ Register TagPrefix="Utilities" Namespace="Microsoft.SharePoint.Utilities" Assembly="Microsoft.SharePoint, Version=15.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>
<%@ Register TagPrefix="asp" Namespace="System.Web.UI" Assembly="System.Web.Extensions, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" %>
<%@ Import Namespace="Microsoft.SharePoint" %>
<%@ Register TagPrefix="WebPartPages" Namespace="Microsoft.SharePoint.WebPartPages" Assembly="Microsoft.SharePoint, Version=15.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>
<%@ Control Language="C#" AutoEventWireup="true" CodeBehind="VisualWebPart1.ascx.cs" Inherits="RotattingBanner.VisualWebPart1.VisualWebPart1" %>
<link type="text/css" rel="stylesheet" href="../_layouts/15/RotattingBanner/flexslider.css" />
<link type="text/css" rel="stylesheet" href="//cdnjs.cloudflare.com/ajax/libs/font-awesome/4.2.0/css/font-awesome.min.css"/>
<script type="text/javascript" src="//code.jquery.com/jquery-2.1.1.min.js"></script>
<script type="text/javascript" src="../_layouts/15/RotattingBanner/jquery.flexslider-min.js"></script>

<div class="flexslider">
    <ul class="slides">
    </ul>
</div>
<script type="text/javascript">
    $(function () {

        var homepageBannerList = [];
        var bannerURL = _spPageContextInfo.webAbsoluteUrl + "/_api/web/lists/getbytitle('Home Page Banner')/items?$select=Target_x0020_URL,Title,Embedded_x0020_Text,Embedded_x0020_Text_x0020_Color,TitleColor,FileRef,Sort_x0020_Order&$orderby=Sort_x0020_Order&$filter=Enabled eq 1";
        $.ajax({
            url: bannerURL,
            method: "GET",
            headers: { "Accept": "application/json; odata=verbose" },
            async: false,
            success: function (data) {
                $.each(data.d.results, function (i, val) {
                    homepageBannerList.push({ TargetURL: val["Target_x0020_URL"]["Url"], ImageURL: val["FileRef"], Title: val["Title"], TitleColor: val["TitleColor"], Description: val["Embedded_x0020_Text"], EmbeddedTextColor: val["Embedded_x0020_Text_x0020_Color"] });
                });
                var bannerHtml = "";
                for (var i = 0; i < homepageBannerList.length; i++) {
                    bannerHtml += "<li><a href='" + homepageBannerList[i].TargetURL + "'><img src='" + homepageBannerList[i].ImageURL + "'/><a/><div class='slide-caption'><h1 style='color:" + homepageBannerList[i].TitleColor + "'>" + homepageBannerList[i].Title + "</h1><div style='color:" + homepageBannerList[i].EmbeddedTextColor + "'>" + homepageBannerList[i].Description + "</div></div></div></li>";
                }
                $(".flexslider ul").html(bannerHtml);
            },
            error: function (data) {
                alert("");
            }
        });

        $('.flexslider').flexslider({
            animation: "slide",
            slideshow: true,               //Slideshow: true or false
            slideshowSpeed: 5500,           //Slideshow speed: numeric
            animationDuration: 3000,         //Duration: numeric
            directionNav: false,             //Next/Prev: true or false
            animationLoop: true,
            pauseOnHover: true,
            controlNav: true,
            slideshow: true,
            smoothHeight: true
        });
    });
</script>

Now if you add the web part in your SharePoint site you will get the default behavior of Flex Slider 2. But we need to overwrite the default behavior of custom control.
We need to change the css, provided by the Flex Slider. So I removed .flex-control-paging li a property from the css file so that we can add Font Awesome Icon as Flex Slider paging. I also removed some padding, margin, shadow etc from the css file to make the sliding perfect and to fit in a 1024 width design. So the total updated css is:

.flex-container a:active,
.flexslider a:active,
.flex-container a:focus,
.flexslider a:focus {
    outline: none;
}

.slide-caption {
    bottom: 45%;
    color: #FFFFFF;
    position: absolute;
    margin-left: 35px;
}

    .slide-caption h1 {
        color: white;
        clear: both;
        font-weight: normal;
        font-family: verdana;
    }

    .slide-caption div {
        color: #ffffff;
        clear: both;
        font-size: 16px;
        text-shadow: 0 6px 14px black;
        width: 50%;
        font-weight: normal;
        font-family: verdana;
    }

.ms-rtestate-field p, p.ms-rteElement-P {
    margin: 0;
    line-height: 0;
}

.slide-caption a {
    background-color: #83d62b;
    font-size: 14px;
    font-style: normal;
    border: 1px solid transparent;
    padding: 5px 15px;
    color: white;
    font-family: verdana;
    border-color: ButtonHighlight ButtonShadow ButtonShadow ButtonHighlight;
    margin-top: 1%;
    float: left;
}

    .slide-caption a:hover {
        text-decoration: none;
    }

.ms-rte-layoutszone-inner {
    padding: 0px;
}

.ms-rte-layoutszone-inner {
    border: 0;
    margin: 0;
    padding: 0;
}

.slides,
.flex-control-nav,
.flex-direction-nav {
    margin: 0;
    padding: 0;
    list-style: none;
}

/* Icon Fonts
*********************************/
/* Font-face Icons */
/*@font-face {
    font-family: 'flexslider-icon';
    src: url('fonts/flexslider-icon.eot');
    src: url('fonts/flexslider-icon.eot?#iefix') format('embedded-opentype'), url('fonts/flexslider-icon.woff') format('woff'), url('fonts/flexslider-icon.ttf') format('truetype'), url('fonts/flexslider-icon.svg#flexslider-icon') format('svg');
    font-weight: normal;
    font-style: normal;
}*/

/* FlexSlider Necessary Styles
*********************************/
.flexslider {
    margin: 0;
    padding: 0;
    font-family: Verdana;
}

    .flexslider .slides li {
        width: 1024px;
        position: relative;
    }

    .flexslider .slides &amp;gt; li {
        display: none;
        -webkit-backface-visibility: hidden;
        width: 1024px;
    }
    /* Hide the slides before the JS is loaded. Avoids image jumping */
    .flexslider .slides img {
        display: block;
    }

.flex-pauseplay span {
    text-transform: capitalize;
}

/* Clearfix for the .slides element */
.slides:after {
    content: &amp;quot;\0020&amp;quot;;
    display: block;
    clear: both;
    visibility: hidden;
    line-height: 0;
    height: 0;
}

html[xmlns] .slides {
    display: block;
}

* html .slides {
    height: 1%;
}

/* No JavaScript Fallback */
/* If you are not using another script, such as Modernizr, make sure you
 * include js that eliminates this class on page load */
.no-js .slides &amp;gt; li:first-child {
    display: block;
}

/* FlexSlider Default Theme
*********************************/
.flexslider {
    position: relative;
}

.flex-viewport {
    max-height: 2000px;
    -webkit-transition: all 1s ease;
    -moz-transition: all 1s ease;
    -o-transition: all 1s ease;
    transition: all 1s ease;
}

.loading .flex-viewport {
    max-height: 298px;
}

.flexslider .slides {
    zoom: 1;
}

.carousel li {
    margin-right: 5px;
}

/* Direction Nav */
.flex-direction-nav {
    *height: 0;
}

    .flex-direction-nav a {
        text-decoration: none;
        display: block;
        width: 40px;
        height: 40px;
        margin: -20px 0 0;
        position: absolute;
        top: 50%;
        z-index: 10;
        overflow: hidden;
        opacity: 0;
        cursor: pointer;
        color: rgba(0,0,0,0.8);
        text-shadow: 1px 1px 0 rgba(255,255,255,0.3);
        -webkit-transition: all .3s ease;
        -moz-transition: all .3s ease;
        transition: all .3s ease;
    }

    .flex-direction-nav .flex-prev {
        left: -50px;
    }

    .flex-direction-nav .flex-next {
        right: -50px;
        text-align: right;
    }

.flexslider:hover .flex-prev {
    opacity: 0.7;
    left: 10px;
}

.flexslider:hover .flex-next {
    opacity: 0.7;
    right: 10px;
}

    .flexslider:hover .flex-next:hover, .flexslider:hover .flex-prev:hover {
        opacity: 1;
    }

.flex-direction-nav .flex-disabled {
    opacity: 0!important;
    filter: alpha(opacity=0);
    cursor: default;
}

.flex-direction-nav a:before {
    font-family: &amp;quot;flexslider-icon&amp;quot;;
    font-size: 40px;
    display: inline-block;
    content: '\f001';
}

.flex-direction-nav a::before {
}

.flex-direction-nav a.flex-next:before {
    content: '\f002';
}

/* Pause/Play */
.flex-pauseplay a {
    display: block;
    width: 20px;
    height: 20px;
    position: absolute;
    bottom: 5px;
    left: 10px;
    opacity: 0.8;
    z-index: 10;
    overflow: hidden;
    cursor: pointer;
    color: #000;
}

    .flex-pauseplay a:before {
        font-family: &amp;quot;flexslider-icon&amp;quot;;
        font-size: 20px;
        display: inline-block;
        content: '\f004';
    }

    .flex-pauseplay a:hover {
        opacity: 1;
    }

    .flex-pauseplay a.flex-play:before {
        content: '\f003';
    }

/* Control Nav */
.flex-control-nav {
    width: 100%;
    position: absolute;
    bottom: 10%;
    text-align: center;
}

    .flex-control-nav .fa {
        color: rgb(255, 255, 255);
        font-size: 24px;
        cursor: pointer;
    }

    .flex-control-nav li {
        padding: 7px;
        display: inline-block;
        zoom: 1;
    }

        .flex-control-nav li a {
            padding: 7px;
            text-shadow: 6px 6px 30px rgba(0, 0, 0, 1);
        }

.flex-control-thumbs {
    margin: 5px 0 0;
    position: static;
    overflow: hidden;
}

    .flex-control-thumbs li {
        width: 25%;
        float: left;
        margin: 0;
    }

    .flex-control-thumbs img {
        width: 100%;
        display: block;
        opacity: .7;
        cursor: pointer;
    }

        .flex-control-thumbs img:hover {
            opacity: 1;
        }

    .flex-control-thumbs .flex-active {
        opacity: 1;
        cursor: default;
    }

@media screen and (max-width: 860px) {
    .flex-direction-nav .flex-prev {
        opacity: 1;
        left: 10px;
    }

    .flex-direction-nav .flex-next {
        opacity: 1;
        right: 10px;
    }
}

If we look into the Flex Slider JavaScript plugin, we see that the default pagination is generated by the Javascript code. We need to add the font awesome icon class to the existing anchor tag generated by the plugin. To do that, we also need to make a REST call in the plugin to get the Font Awesome icon class from the Home Page Banner list. In the plugin code find the controlNav and after that make a REST call like below:

controlNav: {
    setup: function () {
        d.manualControls ? p.controlNav.setupManual() : p.controlNav.setupPaging()
    },
    setupPaging: function () {
        var f, g, b = "thumbnails" === d.vars.controlNav ? "control-thumbs" : "control-paging",
            c = 1;
        var iconList = [];
        var self = this;
        //Magic starts here  with ajax call
        $.ajax({
            url: _spPageContextInfo.webAbsoluteUrl + "/_api/Web/Lists/getByTitle('Home Page Banner')/items",
            method: "GET",
            async: false,
            headers: {
                "Accept": "application/json; odata=verbose"
            },
            success: function (data) {
                $.each(data.d.results, function (i, val) {
                    iconList.push({
                        CssClass: val["FontAwesomeIconClass"],
                        IconHoverText: val["FontAwesomeIconHoverText"],
                        IconColor: val["IconColor"]
                    });
                });

            },
            error: function (jq, status, message) {
                alert('A jQuery error has occurred. Status: ' + status + ' - Message: ' + message);
            }
        });
        if (d.controlNavScaffold = a('<ol class="' + e + "control-nav " + e + b + '"></ol>'), d.pagingCount > 1) for (var j = 0; j < d.pagingCount; j++) {

            if (g = d.slides.eq(j), f = "thumbnails" === d.vars.controlNav ? '<img src="' + g.attr("data-thumb") + '"/>' : "<a title='" + iconList[j].IconHoverText + "'><i class='" + iconList[j].CssClass + "' style='color:" + iconList[j].IconColor + "'></i></a>", "thumbnails" === d.vars.controlNav && !0 === d.vars.thumbCaptions) {
                var k = g.attr("data-thumbcaption");
                "" != k && void 0 != k && (f += '<span class="' + e + 'caption">' + k + "</span>")
            }
            d.controlNavScaffold.append("<li>" + f + "</li>"),
            c++
        }
        d.controlsContainer ? a(d.controlsContainer).append(d.controlNavScaffold) : d.append(d.controlNavScaffold), p.controlNav.set(), p.controlNav.active(), d.controlNavScaffold.delegate("a, img", h, function (b) {
            if (b.preventDefault(), "" === i || i === b.type) {
                var c = a(this),
                    f = d.controlNav.index(c);
                c.hasClass(e + "active") || (d.direction = f > d.currentSlide ? "next" : "prev", d.flexAnimate(f, d.vars.pauseOnAction))
            }
            "" === i && (i = b.type), p.setToClearWatchedEvent()
        })

    },
    setupManual: function () {
        d.controlNav = d.manualControls, p.controlNav.active(), d.controlNav.bind(h, function (b) {
            if (b.preventDefault(), "" === i || i === b.type) {
                var c = a(this),
                    f = d.controlNav.index(c);
                c.hasClass(e + "active") || (d.direction = f > d.currentSlide ? "next" : "prev", d.flexAnimate(f, d.vars.pauseOnAction))
            }
            "" === i && (i = b.type), p.setToClearWatchedEvent()
        })
    },
    set: function () {
        var b = "thumbnails" === d.vars.controlNav ? "img" : "a";
        d.controlNav = a("." + e + "control-nav li " + b, d.controlsContainer ? d.controlsContainer : d)
    },
    active: function () {
        d.controlNav.removeClass(e + "active").eq(d.animatingTo).addClass(e + "active")
    },
    update: function (b, c) {
        d.pagingCount > 1 && "add" === b ? d.controlNavScaffold.append(a("<li><a>" + d.count + "</a></li>")) : 1 === d.pagingCount ? d.controlNavScaffold.find("li").remove() : d.controlNav.eq(c).closest("li").remove(), p.controlNav.set(), d.pagingCount > 1 && d.pagingCount !== d.controlNav.length ? d.update(c, b) : p.controlNav.active()
    }
}

We added our Font Awesome Icon, it’s color and it’s title from the iconList[] array to the default anchor tag.

All the development is done. If we deploy the web part we can see the result:9

You can find the whole project in my github repository