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

Advertisements

6 thoughts on “Sharepoint rotating banner with custom pagination control using font awesome

  1. Hi S.M. Forhad Ali
    I have downloaded the project but unable to view the pictures via the webpart do you have a template for the picture library just to ensure that I am using the right columns and stuff ?

    Like

  2. Hi Pabs,
    I am sorry to say I don’t have any template for the picture library. Its quite easy, as you can see all the column names are visible in the tutorial. Another easy way is to find the column names in the code.

    Thanks

    Like

  3. Dear Forhad,
    I am trying to deploy your webpart in sandbox solution but it doesn’t work. I checked every line in the code and column name as well. I am getting empty webpart with no images.

    Like

  4. Hi Irshad,

    Did you check your browser’s console?
    Did you hit the rest api url on your browser (does it shows any data?)
    Could you please share me the output of the REST API Url’s output?

    Like

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s