Skip to content

Getting started with REST in SharePoint 2013 – Part VI

Welcome to the sixt post in this series about REST in SharePoint 2013. In the previous posts I wrote about how to get external data into your SharePoint page. This time I’m stepping back into how to read information from SharePoint, and this time we will take a look into an example about how to use the SharePoint 2013 Search REST API, one of the most powerful REST access points in SharePoint, and yes, this will work the same no matter if it’s SharePoint Online or SharePoint Onprem.

Please read the previous posts in this series before you go on to this post:

SharePoint 2013 Search REST API

First of all, take a look at the overview at Office Dev center: http://msdn.microsoft.com/en-us/library/office/jj163876(v=office.15).aspx – from this page you can learn all the basic stuff about how to construct queries and parameters. The REST Search API gives a lot of possibilities, you can basically retrive just anything that the serach in SharePoint will index! Take a look at Chris O’Briens blog post as an cool example about how to use REST search API, an example that shows how to get related items to the content in an app.

In the following example I’ll show you how to create a table based on a search Query, just a single Word that’s stored as a variable. Instead of the Word ‘SharePoint’ you could for example store something more dynamic like a metadata onto the current page. Let’s say you add this in a page layout and use it to display other pages that are in some way related to this page.

App

Let’g go!

 

var queryText = 'SharePoint'
var startrow = '&startrow=0'
var rowlimit = '&rowlimit=10'
var searchQuery = _spPageContextInfo.webAbsoluteUrl + "/_api/search/query?querytext='" + queryText + "'" + rowlimit + startrow;

$.ajax({
url: searchQuery,
method: "GET",
headers: {"Accept": "application/json; odata=verbose"},
success: onQuerySuccess,
error: onQueryFail
});

function onQuerySuccess(data) {

var items = [];
items.push("<ul id='listContainer'>");
items.push("<div id='listHeader'>" + 'Search results..' + "</div>");

if (data.d.query.PrimaryQueryResult.RelevantResults.Table.Rows.results.length == 0) {
$("#listResult").append('No results..');
}
else{
$(data.d.query.PrimaryQueryResult.RelevantResults.Table.Rows.results).each(function(){

var path = keyValue(this, 'Path');
var title = keyValue(this, 'Title');
var created = moment(keyValue(this, 'Write')).format("YYYY-MM-DD");
if (!moment(created,'YYYY-MM-DD').isValid()) {
var created = 'Date is not applicable..';
}
else {
var created = moment(keyValue(this, 'Write')).format("YYYY-MM-DD");
}

items.push('<li id="' + 'listContent' + '">' +
'<span id="' + 'listContentInner' + '">' +
'<a href="' + path + '">' +  title + '</a>' +
'</span>' +
'<span id="' + 'listContentInnerTime' + '">' +
' - ' + created +
'</span>' +
'</li>');
});

items.push("</ul>");

$("#listResult").html(items.join(''));

}
}

function keyValue(row, fldName) {
var ret = null;
$.each(row.Cells.results, function () {
if (this.Key == fldName) {
ret = this.Value;
}
});
return ret;
}

function onQueryFail(sender, args) {
$("#listResult").append('Query failed. Error:' + args.get_message());
}

It’s a bit tricky to find the structure of the nodes, but if you using for example Advanced REST client in google chrome you’ll find it. Take a look at this image, hope this will help you to figure out the path for the data results: data.d.query.PrimaryQueryResult.RelevantResults.Table.Rows.results

Nodes

You can download the file from here, including the CSS and script references

Getting started with REST in SharePoint 2013 – Part V

Welcome to the fifth post in this series about REST in SharePoint 2013. In the previous posts I wrote about how you can connect to a external data source with REST, fetching Flickr photos to SharePoint using JSON and jQuery. In this post I will show you another example of how you can build an APP that get external data into your SharePoint page.

Please read the previous posts in this series before you go on to this post:

Display the current weather from your location in SharePoint

I built this one as a SharePoint hosted APP and it’s published at the SharePoint Store. If you want to try the app in your SharePoint Online public or Intranet or maybe your SharePoint 2013 on prem, go to the SharePoint store and add it. You can find more information about the APP at the Office Store

CurrentWeather

Functions

With help of this script, you can display all the necessary stuff about the current or a forcast of the weather for a specific Place. For example:

  • Temperature
  • Wind speed
  • Wind bearing
  • Humidity
  • Pressure

Download the code

Feel free to modify this the way you want and if you find some cool implementations or Changes in the code please add a comment. Download the Visual Studio Projects here with all stuff included.

Just a few notes about the APP

Basically, I’m using the forecast.IO API to get the weather. You need an API key, and it’s free up to 1000 calls per day and they have a great documentation of the API. In the APP i do also use ‘auto position’ as an option in the APP part settings, I did not used the HTML5 Geolocation because The HTML5 Geolocation specification mandates that before any location data can be retrieved the browser first request permission from the user to share its location.

Only when the user allows does the browser retrieves the users location. Therefore I thought it would be enough to use the client’ IP information, in most cases it’s ok, however if your ISP have routing your autoposition will not work perfect so I added the option to turn of ‘Autoposition’ and instead you can add an exact position with Longitude and Latitude coordinates.

In order to get a name for the location, in case you using autoposition I called Google maps API. This API don’t support HTTPS to take care about this cross domain issue for IE 8 and 9 the solution is to write a little Proxy as a condition.

Note that if you don’t want the autoposition option, you can just use the forecast.IO API, no need for Google Map API or the Free IP services.

        function crossDomainAjax(url, successCallback) {
                // IE8 & 9 only Cross domain JSON GET request
                if ('XDomainRequest' in window && window.XDomainRequest !== null) {
                    var xdr = new XDomainRequest(); // Use Microsoft XDR
                    xdr.open('get', url);
                    xdr.onload = function () {
                        var dom = new ActiveXObject('Microsoft.XMLDOM'),
                            JSON = $.parseJSON(xdr.responseText);
                        dom.async = false;
                        if (JSON == null || typeof (JSON) == 'undefined') {
                            JSON = $.parseJSON(data.firstChild.textContent);
                        }
                        successCallback(JSON);
                    };
                    xdr.onerror = function () {
                        _result = false;
                    };
                    xdr.send();
                }
                    // End IE8 & 9 only Cross domain JSON GET request
                    // Do normal jQuery AJAX for everything else          
                else {
                    $.ajax({
                        url: urlGoogle + lati + ',' + longi + "&sensor=false",
                        cache: false,
                        dataType: 'json',
                        type: 'GET',
                        success: function (data, success) {
                            successCallback(data);
                        }
                    });
                }
                // End Do normal jQuery AJAX for everything else  
        }

If you don’t want to use this as a APP, it’s just JS/HTML/CSS so you can modify this and implement this into a content editor, a page layout or into a web part, maybe as a part in the header for the start page? This script can be implemented in many different ways.

barc Read more…

Getting started with REST in SharePoint 2013 – Part IV

Welcome to the fourth post in this series about REST in SharePoint 2013. In the previous posts I wrote about how to interact with SharePoint lists, but now it’s time to look in to how to retrieve information from an external source with help of JSON. There’s a lot of web services with APIs that provides JSON like Facebook, Twitter, Foursquare, bing maps, Netflix. Yahoo weather and many many more. In this post I’ll show you an easy example of how to get information from Flickr, as you may know a popular photo-sharing site that has been around for years and has now 5 billions of photos. And yes, this will work the same no matter if it’s SharePoint Online (public or internal) or SharePoint Onprem.

Please read the previous posts in this series before you go on to this post:

Bring Flickr photos to SharePoint using JSON and jQuery

The following code will give you a quick start to read the latest 3 images from my account at Flickr. You’ll see my id ‘69239123@N08′, please change this with you own ID. To find your ID, go to this page: http://idgettr.com/. You can add the following script into a content editor web part or use SharePoint Designer and it into a page. If you only want to display the latest image, change 4 to 0 in the return false. Don’t forget to reference to latest jquery as well.

Before you start scripting, take a look at the documentation at Flickr API here

<script type="text/javascript">
$.getJSON("https://api.flickr.com/services/feeds/photos_public.gne?id=69239123@N08&format=json&jsoncallback=?", 
function(data){
$.each(data.items, function(i,item){
	$("<img/>").attr("src", item.media.m).appendTo("#images")
		.wrap("<a href='" + item.link + "'></a>");
		if ( i == 4 ) return false;
	});
});
</script>	
<div id="images"></div>	

FlickR

Extended version

Ok, the following script is similar to the one above but have some styling and is more template based, prepared to extend with your own HTML, for example if you would like to create an image slider out of the images. You’ll also have some settings like tags i the code.

<style type="text/css">
.thumbs li {list-style: none; float: left; margin: 5px; padding: 3px; background: #eee; -moz-box-shadow: 0 0 4px #444; -webkit-box-shadow: 0 0 2px #000}
.thumbs li a {}
.thumbs li img { display: block; height: 350px}
.thumbs li a img { border: none}
#flickrRheader{font-size:x-large;display:block;text-align:center}
#flickrRdescription{font-size: small;display:block;text-align:center}
#flicRUserID{display:none}
}
</style>

<div id="flicRUserID">69239123@N08</div>
<div id="flickRcontainer">
	<ul id="custom" class="thumbs"></ul>
</div>

<script type="text/javascript" src="https://ajax.aspnetcdn.com/ajax/jQuery/jquery-1.11.1.min.js"></script>

<script type="text/javascript">
(function($) {
	$.fn.jflickrfeed = function(settings, callback) {
		settings = $.extend(true, {
			flickrbase: 'https://api.flickr.com/services/feeds/',
			feedapi: 'photos_public.gne',
			qstrings: {
			    //tags: "SharePoint",
				format: 'json',
				jsoncallback: '?'
			},
			cleanDescription: true,
			useTemplate: true,
			itemTemplate: '',
			itemCallback: function(){}
		}, settings);

		var url = settings.flickrbase + settings.feedapi + '?';
		var first = true;

		for(var key in settings.qstrings){
			if(!first)
				url += '&';
			url += key + '=' + settings.qstrings[key];
			first = false;
		}

		return $(this).each(function(){
			var $flickRcontainer = $(this);
			var flickRcontainer = this;
			$.getJSON(url, function(data){
				$.each(data.items, function(i,item){
					if(i < settings.limit){
						// Add Image Sizes
						// http://www.flickr.com/services/api/misc.urls.html
						item['image_s'] = item.media.m.replace('_m', '_s');
						item['image_t'] = item.media.m.replace('_m', '_t');
						item['image_m'] = item.media.m.replace('_m', '_m');
						item['image'] = item.media.m.replace('_m', '');
						item['image_b'] = item.media.m.replace('_m', '_b');
						delete item.media;
						// Template
						if(settings.useTemplate){
							var template = settings.itemTemplate;
							for(var key in item){
								var rgx = new RegExp('{{' + key + '}}', 'g');
								template = template.replace(rgx, item[key]);
							}
							$flickRcontainer.append(template)
						}
						
						//itemCallback
						settings.itemCallback.call(flickRcontainer, item);
					}
				});
				if($.isFunction(callback)){
					callback.call(flickRcontainer, data);
				}
			});
		});
	}
})(jQuery);

$(document).ready(function(){
var flickRuser = $("#flicRUserID").html();
	$('#custom').jflickrfeed({
		limit: 1,
		qstrings: {
			id: flickRuser		
		},
		itemTemplate: '<li>'+
		'<a href="{{image}}" title="{{title}}">' +
		'<img src="{{image}}" alt="{{title}}" />' +
		'</a>' +
		'<span id="flickrRheader">{{title}}</span>' +
    	'</li>'
	});
});

</script>

If you like to have this packed as an app, you can dynamic handle the parameters like user ID and number of photos into the settings of the APP. I have a VS2013 project you can download and modify here.

VSsettings

In the next post I’ll show you how to create a current weather app with REST and JSON, with help from developer.io weather service. Stay in tune!

Getting started with REST in SharePoint 2013 – Part III

Welcome to the third post in this series about REST in SharePoint 2013, this post is a follow up to the previous post about how to create a web part with help of REST web service that will display something from a SharePoint list. In this post I’ll show you how to use the same approach but integrate a typical jQuery plugin, a image slider to the REST script. This will work the same no matter if it’s SharePoint Online or Onprem.

gondolas

The goal in this post is to create a jquery image slide using content editor web-part or in a single page and of course, if you prefer you can pack this a web part with Visual Studio instead. There’s a lot of jQuery sliders out there, in this example I used Basic jQuery Slider I like this plugin because it’s simple and lightweight and are easy to style in many different ways.
There are two core files required to get up and running with Basic jQuery Slider, the JavaScript plugin and the jQuery library plus a portion of css for the styling. Take a look at the refererences and the css in a single page you can download from here .

One thing to note about the REST script is that the ajax call happens asynchronously, so it’s important that you initialize the slider inside the ajax success callback. Do also note that I’ve created a couple of variables for the image path and build the URL with jQuery’s Pop, Split and Shift methods. That’s because I wanted to read from the automatic thumbnail folder (_w) instead of the the folder for the full image.

I hope this post gives you some inspiration to get started to create web parts displaying something from SharePoint lists, and there’s a plenty of useful jQuery plugins for different kind of task to play around with out there!

Please read the first two posts before you go on to this post:

Create a image slider with REST

if (_spPageContextInfo.webServerRelativeUrl === '/') {
	var webUrl = '';
}    
else{
	var webUrl = _spPageContextInfo.webServerRelativeUrl;
}

// start ajax
$.ajax({
	url: webUrl + "/_api/Lists/GetByTitle('PublicImages')/items?$select=EncodedAbsUrl,Title",
	type: "GET",
	headers: {"Accept": "application/json;odata=verbose"},
	cache:false,
	// start success                  
	success: function(data){
	
		var items = [];
		 	items.push("<div id='banner-slide'>");
			items.push("<ul class='bjqs'>");
	        
		// if content exist
		var dataResult = data.d.results;
		    if (dataResult.length == 0) {
		        items.push("<div id='listNoRecords'>" + 'No images were found..' + "</div>");
		    }    
		    else{
				// start data.d.results
				$(data.d.results).each(function(){
				var imgURL = this.EncodedAbsUrl;
				var mainurl = imgURL.substring(0, imgURL.lastIndexOf("/") + 1);			
				var fileextension = imgURL.substring(imgURL.lastIndexOf(".") + 1, imgURL.length);
				var imgnameVar = imgURL, imgname;
					imgname = imgnameVar.split('/').pop().split('.').shift(); 
				var thumb = '_w/';
				var extension = '.JPG';

				items.push('<li>' + 
				        	' <img src="' + mainurl + thumb + imgname + '_' + fileextension + extension + '"/' + 'title='  +'"' + this.Title +'"' + ' />' +
				    	   '</li>');
	
				});
				// end data.d.results		
	    	}    
	    	// end if content exist
				
				items.push("</ul>");
				items.push("</div>");

				// Add HTML and it's content to the listResult div
				$("#listResult").html(items.join(''));
				
				// Start Image Slider
				$('#banner-slide').bjqs({
					animtype      : 'slide', //fade
		            width         : 340,
					animduration : 450, // how fast the animation are
					animspeed : 4000, // the delay between each slide
					showcontrols : false, // show next and prev controls
					showmarkers : true, // Show individual slide markers
					centermarkers : true, // Center markers horizontally
					keyboardnav : true, // enable keyboard navigation
					hoverpause : true, // pause the slider on hover
					usecaptions : true, // show captions for images using the image title tag
					randomstart : true // start slider at random slide
				});

	}
	// end success  
	
});
// end ajax

I will be back soon so stay tuned for the next post!

Getting started with REST in SharePoint 2013 – Part II

Welcome to the second post in this series about REST in SharePoint 2013. Please read the first post before you go on to this post Get started with REST in SharePoint 2013 – Part I

In this post I will show you how create a web part with help of REST web service that will display a list of all sub sites immediately below the current site, similar to what you can find under ‘Site Contents’. We’ll also need to have this permission trimmed.

subsites

Before you start scripting and build the HTML and CSS for this, you’ll first need to construct the RESTful HTTP / oData request in order to retrieve the entities, in this case all sub sites of some site. Assume you have a number of sub sites under a site named Projects. Change the domain name and try the following basic query in your browser.

https://contoso.sharepoint.com/projects/_api/web/webs/?$select=title

Once you get the results back in your browser in pure XML and you have construct the query properly with the filters you want, it’s time to create the script that will return the result in JSON format and will create the markup with the styling.

Let’s start

You can use notepad, SharePoint Designer or Visual Studio or the tool of your choice. For example you can just add the following script, the CSS and the jQuery references in one single text file to a folder in your SharePoint environment and use a content editor web part to link to the text file.

Here’s the script that will create a list of all sub sites. You can download the script with the CSS and jQuery references from here.

<div id="listResult"></div>
<script type="text/javascript">
// If the web part will live in the root web or a subsite
if (_spPageContextInfo.webServerRelativeUrl === '/') {
var webUrl = '';
}    
else{
var webUrl = _spPageContextInfo.webServerRelativeUrl;
}
// start ajax
$.ajax({
url: webUrl + "/_api/web/webs/?$select=title,ServerRelativeUrl,Created,effectivebasepermissions&$filter=(effectivebasepermissions/high%20gt%2032)&$orderby=Created desc",

type: "GET",
headers: {"Accept": "application/json;odata=verbose"},
cache:false,
// start success                  
success: function(data){
//console.log(data);
var items = [];
items.push("<ul id='listContainer'>");
items.push("<div id='listHeader'>" + 'Subsites ' + "</div>");     
// if content exist
var dataResult = data.d.results;
if (dataResult.length == 0) {
items.push("<div id='listNoRecords'>" + 'No subsites were found' + "</div>");
}    
else{
// start data.d.results
$(data.d.results).each(function(){
var CreatedDate = moment(this.Created).startOf('hour').fromNow()
items.push('<li id="' + 'listContent' + '">' + 
'<span id="' + 'listContentInner' + '">' + 
'<img src="/_layouts/15/images/SharePointFoundation16.png" />' + ' <a href="' + this.ServerRelativeUrl + '">' +  this.Title + '</a>' +  
'</span>' + 
'<span id="' + 'listContentInnerTime' + '">' + 
' - ' + CreatedDate + 
'</span>' + 
'</li>');			    		
});
// end data.d.results		
}    
// end if content exist
items.push("</ul>");
$("#listResult").html(items.join(''));
}
// end success  
});
// end ajax
</script>
<script type="text/javascript" src="https://ajax.aspnetcdn.com/ajax/jQuery/jquery-1.9.1.min.js"></script>
<script type="text/javascript" src="//cdnjs.cloudflare.com/ajax/libs/moment.js/2.6.0/moment.min.js"></script>

A couple of things

Filter and sorting

You can filter the oData query by conditions or sort the result, for example:

  • $filter=ID eq 1 (only the object with ID eq to 1)
  • $top=5 (limit to 5 items)
  • $orderby=Created desc (sort by descending order)

There’s a lot of oData operators that are supported in SharePoint’s REST service like numeric comparsions, string comparsions and Date/TIme functions. Read more about this at MSDN.

Add the results to the DOM

All the data in the array are stored in a variable called Items. The trick I used in the script for appending the data to the DOM is to use jQuery’s Push() method, in this way you’ll have good control of the HTML you create.

_spPageContextInfo

In this example I added a condition that will add a slash to the beginning of the URI if it’s not a top site, otherwise I don’t want this trailing slash there. The _spPageContextInfo will simply get the site paths after the domain name.

if (_spPageContextInfo.webServerRelativeUrl === '/') {
var webUrl = '';
}    
else{
var webUrl = _spPageContextInfo.webServerRelativeUrl;
}
url: webUrl + "/_api/web/webs/?$select=title,ServerRelativeUrl,Created,effectivebasepermissions&$filter=(effectivebasepermissions/high%20gt%2032)&$orderby=Created desc",

Date parsing

The REST API in SharePoint returns the date in ISO8601 which means that you’ll get the date and time back in a format like this: 2014-06-30T22:56:00Z. To format date and time in JS is tricky. To avoid this I’ve used a great JS plugin called Moment.js this one will help you and take care of the parsing. MomentJS will also give you the option to display the result in a clean way like 2014-06-30 or for example a format like ‘1 month ago’.

Security trimming

The result from a REST query are not security trimmed so if you want to display only the sites for which the users has access to, you need to secure trim the REST URI with a filter using the EffectiveBasePermissions with a following parameter like this

filter=(effectivebasepermissions/high%20gt%2032)

There’s a permission in SharePoint to allow web service called “Use Remote Interfaces”. All users should have this permission to be able to read results from a REST call.

If you have users in the out of the box group ‘visitors’ which have the permission level = Read, you’ll need to add ‘Use Remote Interfaces’ to this permission level. You can find the page with this URL: http://YourSite/_layouts/15/editrole.aspx?role=Read
URI

Do also note that the ‘Use Remote Interfaces’ can be disabled and enabled on the Web Application level in central admin.

Do always test your REST calls for users with different permission levels.

Stay tuned for the next post in this series!

</christian>

Getting started with REST in SharePoint 2013 – Part I

Welcome to my new series about using REST in SharePoint 2013! My intention in writing this is to show some quick and easy to follow examples of how to use REST web services (Representational State Transfer) and oData to access and querying in SharePoint 2013 and all this will be in focused on the user interface, the branding and web development aspects of using REST in SharePoint, like how to retrieve and manipulate list data or site data, how to create ‘data views’, rollups using latest standards of HTML, CSS and jQuery spiced with Ajax.

If you have previously worked with XSLT and data view web parts I hope this series will bring some inspiration to get going with JS for your apps, web parts or pages in SharePoint.

REST-1

This image shows an example of how you can roll up items from a list, toggling for more information and filter by some metadata. More about this in one of the upcoming posts

With REST you can make an http request to get information from different kinds of data sources like a SharePoint list. If you try it in your browser it would be just like going to a website but instead of returning a web page, you will get back the data in XML.

In other words you can easily consume the services in SharePoint that the API offers like list data, social feeds or search if you for example needs to expose its content in an app or similar. REST do also permits the data formats XML or JSON and supports CRUD operations. REST is one of the main APIs that are provided in SharePoint 2013, foundation or server and SharePoint Online but it’s not enabled for a public SharePoint online site over http.

I’ll not going into all the technical details here, read more about REST at Office Dev Center – MSDN library. [http://msdn.microsoft.com/en-us/library/office/jj164022(v=office.15).aspx]

Now let’s look into on how to start use REST/oData to fetch information from a SharePoint list.

Part 1 – A basic example

In this example we’ll examine how to access the REST/oData web services direct in the browser. Just replace the https://contoso/ with your URL. Furthermore make sure you have a document library in the site with the name Documents including some documents. Just make sure you have permission to access this site and the library.

  1. Paste this URL in your browser and hit enter:
    https://contoso/_api/web/lists/getbytitle('Documents')/items?$select=Title

    – the browser will now give you the desired result in XML.

  2. Now it’s time to parse the XML into a human readable format. To do this, I push the objects in the array into HTML and set the style with CSS.

    Use Visual Studio or SharePoint Designer and create an empty .aspx page for example in the root web in SharePoint to try this out. If you prefer you can also add the script, HTML and CSS into a .txt file and link this file by using the content editor web part. This will work in SharePoint Online or in SharePoint on prem, but not for and public site in SharePoint Online with HTTP.

    Download the page here to take a look.

    The key point is the script which looks like this:

$.ajax({
url: "/_api/web/lists/getbytitle('Documents')/items?$select=Title&$top=5",
type: "GET",
headers: {"Accept": "application/json;odata=verbose"},
cache:false,                
success: function(data){
console.log(data);
var items = [];
$(data.d.results).each(function(){
items.push('<ul id="' + 'listUL' + '">' + 
'<li id="' + 'listLI' + '">' + 
this.Title +
'</li>' + 
'</ul>');
});
items.push("</div>");
$("#listResult").html(items.join(''))}
}); 

Note that you need to add an reference to jQuery One thing to note is that the URL have a limitation of 256 characters, for normally usages like according to my examples in this series this shouldn’t be any issues, and if you need to more that the limit allows you can use CSOM with for example an old good CAML query or maybe use an data view web part instead.

In the next post I’ll will write more about how to build the queries with help of the following options:

  • Select
  • Filter
  • Expand
  • Order by
  • Filter
  • Top

I will also show a bit more advanced example of how to create a rollup of ‘the latest 5 blog posts’ on the start page of the home site including HTML and CSS for the UI.

More posts will come and here’s a list of some of the topics I will write about:

  • More examples of how to work with SharePoint lists and site information
  • Tools for site exploring, query building, debugging and JSON viewing
  • How to create and Image slideshow
  • Using REST to get external content
  • CRUD operations (Create Read Update Delete)
  • Using Knockout or Angular for data binding
  • Using DataTables, MixItUp and Moment.js for stuff like sorting, pagination and date parsing
  • Interact to the user profiles with help of SPservices
  • Packing you REST script as an APP

I will be back soon so stay tuned for the next post!

SharePoint Server MVP 2014

I’m very happy to announce that I’ve been renewed with the award SharePoint MVP 2014 by Microsoft for the fourth time in a row!

MVP2014

To receive this award again makes me really proud and of course motivates me to keep on writing articles, speaking at conferences and participate in different projects for the community around SharePoint. Many thanks to Microsoft, my MVP lead, colleagues, friends, readers of this blog and all great people out there in the world wide SharePoint community. If you want to know more about the program, read it from the Microsoft MVP site.

Just as Before, you can count on more posts about SharePoint branding and front end development in general. Recently, I have written a blog series about how to customizing SharePoint 2013 global navigation and next up I planning to write a couple of blogs about REST in SharePoint 2013. I think I’ll write this in the APP perspective using NAPA or VS2013. If you got some ideas here regarding the content, just drop a comment.

Furthermore, maybe we will meet on any SharePoint Conference this year>, the next opportunity will be at SharePoint Saturday in Dubai May 17 where I’ll be speaking about SharePoint Branding.

See you around!

/ Christian

Customizing SharePoint 2013 global navigation with CSS and jQuery – Part 5

Time for the last post in the series about how to customize the global navigation in SharePoint 2013. In this post, you get two new examples of how you can customize the navigation with the help of CSS. This will work for SharePoint 2013, Online or Onprem when using structural navigation.

Nav-Red

Add a nav tag in the master page

I added a nav tag as a container for the SharePoint top menu control. The nav tag is a new tag in HTML 5 and the element should be used for major navigation blocks in the html file. It’s a semantic tag that tells the browser or other reading software such as a search engine that it’s a navigation, compared to a div that just don’t say anything about its content. The CSS is dependent on this nav tag, so if you want to cut & paste, you need to add the nav tag in the master.

<nav>
<SharePoint:AjaxDelta id="DeltaTopNavigation" BlockElement="true" CssClass="ms-displayInline ms-core-navigation" role="navigation" runat="server">
<SharePoint:DelegateControl runat="server" ControlId="TopNavigationDataSource" Id="topNavigationDelegate">
<Template_Controls>
<asp:SiteMapDataSource ShowStartingNode="False" SiteMapProvider="SPNavigationProvider"
id="topSiteMap"	runat="server" StartingNodeUrl="sid:1002"/>
</Template_Controls>
</SharePoint:DelegateControl>
<asp:ContentPlaceHolder id="PlaceHolderTopNavBar" runat="server">
<SharePoint:AspMenu ID="TopNavigationMenu"
Runat="server" EnableViewState="false" DataSourceID="topSiteMap"
AccessKey="<%$Resources:wss,navigation_accesskey%>"
UseSimpleRendering="true" UseSeparateCss="false"
Orientation="Horizontal"
StaticDisplayLevels="2" AdjustForShowStartingNode="true"
MaximumDynamicDisplayLevels="2"	SkipLinkText="" />
</asp:ContentPlaceHolder>
</SharePoint:AjaxDelta>			
</nav>

CSS for the red navigation

In this first example, I use the CSS:after selector to get an arrow and set it’s position relative to it’s parent element, in this I can set the arrow to a selected element with out the use of a image.

#pageTitle{
display:none
}
nav ul li {
background:#dd4433;
border-left: 1px solid #c73d2e;
text-align: center;
height:55px;
}
nav ul li a {
font:16px/36px Arial, Helvetica, sans-serif;
color: #fff;
width:140px;
height:46px;
}
nav{margin:5px auto}
nav ul.root > li.static > ul.static{
border-left:1px #ee4e3d solid;
}
nav .ms-core-navigation .ms-core-listMenu-horizontalBox li.static >  .ms-core-listMenu-item{
margin-right:10px;
padding-top:7px;
margin:0px 0px 0px 0px
}
nav .ms-core-navigation .ms-core-listMenu-item, nav .ms-core-navigation .ms-core-listMenu-item:link, nav .ms-core-navigation .ms-core-listMenu-item:visited{
color:#fff;
}
nav .ms-core-navigation .ms-core-listMenu-horizontalBox ul.static > li.selected > a > span > span{color:#fff}
nav ul li a:hover{color:#000}
nav li{border-right:1px solid #ee4e3d}
nav li:last-child{border-right:0px solid #ee4e3d}
nav li.selected:after{
content:'';
position:relative;
width:0px;
display:block;
left:60px;
border:10px solid transparent;
border-top:8px solid #d43;
}

CSS for the blue navigation

For this blue navigation I use a smooth CSS gradient and a portion of border radius to get the rounded corners. If you want to adjust the width to be stretched relative to it’s content, you can use the out commented paddings instead of the fixed width if you prefer.

Nav-Blue

nav {
overflow:hidden
}
#pageTitle{
display:none
}
nav ul li {
background: #618ba4; /* Old browsers */
background: -moz-linear-gradient(top, #618ba4 0%, #406a82 100%); /* FF3.6+ */
background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#618ba4), color-stop(100%,#406a82)); /* Chrome,Safari4+ */
background: -webkit-linear-gradient(top, #618ba4 0%,#406a82 100%); /* Chrome10+,Safari5.1+ */
background: -o-linear-gradient(top, #618ba4 0%,#406a82 100%); /* Opera 11.10+ */
background: -ms-linear-gradient(top, #618ba4 0%,#406a82 100%); /* IE10+ */
background: linear-gradient(to bottom, #618ba4 0%,#406a82 100%); /* W3C */
filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#618ba4', endColorstr='#406a82',GradientType=0 ); /* IE6-9 */
border-left: 1px solid #7395a8;
border-right: 1px solid #406275;
text-align: center;
height:55px;
}
nav ul li a {
font:16px/36px Arial, Helvetica, sans-serif;
color: #fff;
width:140px;
height:46px;
/*padding-right:20px;padding-left:20px*/
}
nav ul li:last-child {
border-right: none;
border-radius: 0px 5px 5px 0px;
-moz-border-radius: 0px 5px 5px 0px;
-webkit-border-radius: 0px 5px 5px 0px;
}
nav {
margin:1px auto;
border-radius:5px;
}
nav ul.root > li.static > ul.static{
border-left:1px #406a82 solid;
}
nav div > div > ul.static > li.static a:hover{
background: #406a82;
height:46px;
}
nav div > div > ul.static > li.static > ul.static > li:hover {
background: #406a82;
}
nav div > ul.root > li.selected a:hover {
background: #406a82!important;
height:55px;
}
nav .ms-core-navigation .ms-core-listMenu-horizontalBox li.static >  .ms-core-listMenu-item{
margin-right:10px;
padding-top:7px;
margin:0px 0px 0px 0px
}
nav .ms-core-navigation .ms-core-listMenu-item, nav .ms-core-navigation .ms-core-listMenu-item:link, nav .ms-core-navigation .ms-core-listMenu-item:visited{
color:#fff;
}
nav .ms-core-navigation .ms-core-listMenu-horizontalBox ul.static > li.selected > a > span > span{
color: #fff;
}

Take a look at the previous posts here:

I hope you had joy of this posts in the series! Please drop a comment if you have any question.

/ Christian

Customizing SharePoint 2013 global navigation with CSS and jQuery – Part 4

Just as in the previous post, here you got some more examples about how you can spice up the global navigation by add some CSS3. In this post I have included five different kind of link effects animations for you to try out. I’ve used tympanus great piece of work ‘Subtle and modern effects for links or menu items’ tympanus.net/Development/CreativeLinkEffects/ and slightly modified this to work with the markup and CSS of SharePoint 2013.

This is an example of how you can work with CSS3 2D transform methods like translate and scale on pseudo elements (before and after). Take a look at my video on you tube to see this five examples in action!

GlobalNav2013tympanus

Let’s start

You need to add a nav tag in your custom master and some CSS in your exteral CSS file, linked from the master page file. You can change the class name for the nav element to one of this five examples, the available numbers are 1,4,7,12 or 19. For example change cl-effect-1 to cl-effect-4 etc. You can download all the CSS and the navigation control here as well.

Add a nav tag in the master page

I added a nav tag as a container for the SharePoint top menu control. The nav tag is a new tag in HTML 5 and the element should be used for major navigation blocks in the html file. It’s a semantic tag that tells the browser or other reading software such as a search engine that it’s a navigation, compared to a div that just don’t say anything about its content.

<nav class="cl-effect-1">

<SharePoint:AjaxDelta id="DeltaTopNavigation" BlockElement="true" CssClass="ms-displayInline ms-core-navigation" role="navigation" runat="server">
<SharePoint:DelegateControl runat="server" ControlId="TopNavigationDataSource" Id="topNavigationDelegate">
<Template_Controls>
<asp:SiteMapDataSource ShowStartingNode="False" SiteMapProvider="SPNavigationProvider"
id="topSiteMap" runat="server" StartingNodeUrl="sid:1002"/>
</Template_Controls>
</SharePoint:DelegateControl>
<asp:ContentPlaceHolder id="PlaceHolderTopNavBar" runat="server">
<SharePoint:AspMenu ID="TopNavigationMenu"
Runat="server" EnableViewState="false" DataSourceID="topSiteMap"
AccessKey="<%$Resources:wss,navigation_accesskey%>"
UseSimpleRendering="true" UseSeparateCss="false"
Orientation="Horizontal"
StaticDisplayLevels="2" AdjustForShowStartingNode="true"
MaximumDynamicDisplayLevels="2" SkipLinkText="" />
</asp:ContentPlaceHolder>
</SharePoint:AjaxDelta>
			
</nav>

And the CSS

/* ---------- NAVIGATION ---------- */
#pageTitle{display:none!important}
/* general */
nav a {
position: relative;
display: inline-block;
margin: 15px 25px;
outline: none;
color: #fff;
text-decoration: none;
text-transform: uppercase;
letter-spacing: 1px;
font-weight: 400;
text-shadow: 0 0 1px rgba(255,255,255,0.3);
font-size: 1.35em;
}
nav a:hover,
nav a:focus {
outline: none;
}
/* effect type */
/* Effect 1: Brackets */
.cl-effect-1 a::before,
.cl-effect-1 a::after {
display: inline-block;
opacity: 0;
-webkit-transition: -webkit-transform 0.3s, opacity 0.2s;
-moz-transition: -moz-transform 0.3s, opacity 0.2s;
transition: transform 0.3s, opacity 0.2s;
font-weight: 900;
font-size:25px
}
.cl-effect-1 a::before {
margin-right: 10px;
content: '[';
-webkit-transform: translateX(20px);
-moz-transform: translateX(20px);
transform: translateX(20px);
}
.cl-effect-1 a::after {
margin-left: 10px;
content: ']';
-webkit-transform: translateX(-20px);
-moz-transform: translateX(-20px);
transform: translateX(-20px);
}
.cl-effect-1 a:hover::before,
.cl-effect-1 a:hover::after,
.cl-effect-1 a:focus::before,
.cl-effect-1 a:focus::after {
opacity: 1;
-webkit-transform: translateX(0px);
-moz-transform: translateX(0px);
transform: translateX(0px);
}
/* Effect 4: bottom border enlarge */
.cl-effect-4 a {
padding: 0 0 10px;
}
.cl-effect-4 a::after {
position: absolute;
top: 100%;
left: 0;
width: 100%;
height: 1px;
background: #0072C6;
content: '';
opacity: 0;
-webkit-transition: height 0.3s, opacity 0.3s, -webkit-transform 0.3s;
-moz-transition: height 0.3s, opacity 0.3s, -moz-transform 0.3s;
transition: height 0.3s, opacity 0.3s, transform 0.3s;
-webkit-transform: translateY(-10px);
-moz-transform: translateY(-10px);
transform: translateY(-10px);
}
.cl-effect-4 a:hover::after,
.cl-effect-4 a:focus::after {
height: 5px;
opacity: 1;
-webkit-transform: translateY(0px);
-moz-transform: translateY(0px);
transform: translateY(0px);
}
/* Effect 7: second border slides up */
.cl-effect-7 a {
padding: 12px 10px 10px;
color: #566473;
text-shadow: none;
font-weight: 700;
}
.cl-effect-7 a::before,
.cl-effect-7 a::after {
position: absolute;
top: 100%;
left: 0;
width: 100%;
height: 3px;
background: #566473;
content: '';
-webkit-transition: -webkit-transform 0.3s;
-moz-transition: -moz-transform 0.3s;
transition: transform 0.3s;
-webkit-transform: scale(0.85);
-moz-transform: scale(0.85);
transform: scale(0.85);
}
.cl-effect-7 a::after {
opacity: 0;
-webkit-transition: top 0.3s, opacity 0.3s, -webkit-transform 0.3s;
-moz-transition: top 0.3s, opacity 0.3s, -moz-transform 0.3s;
transition: top 0.3s, opacity 0.3s, transform 0.3s;
}
.cl-effect-7 a:hover::before,
.cl-effect-7 a:hover::after,
.cl-effect-7 a:focus::before,
.cl-effect-7 a:focus::after {
-webkit-transform: scale(1);
-moz-transform: scale(1);
transform: scale(1);
}
.cl-effect-7 a:hover::after,
.cl-effect-7 a:focus::after {
top: 0%;
opacity: 1;
}
/* Effect 12: circle */
.cl-effect-12 a::before,
.cl-effect-12 a::after {
position: absolute;
top: 50%;
left: 50%;
width: 70px;
height: 70px;
border: 2px solid rgba(0,0,0,0.1);
border-radius: 50%;
content: '';
opacity: 0;
-webkit-transition: -webkit-transform 0.3s, opacity 0.3s;
-moz-transition: -moz-transform 0.3s, opacity 0.3s;
transition: transform 0.3s, opacity 0.3s;
-webkit-transform: translateX(-50%) translateY(-50%) scale(0.2);
-moz-transform: translateX(-50%) translateY(-50%) scale(0.2);
transform: translateX(-50%) translateY(-50%) scale(0.2);
}
.cl-effect-12 a:hover::before,
.cl-effect-12 a:hover::after,
.cl-effect-12 a:focus::before,
.cl-effect-12 a:focus::after {
opacity: 1;
-webkit-transform: translateX(-50%) translateY(-50%) scale(1);
-moz-transform: translateX(-50%) translateY(-50%) scale(1);
transform: translateX(-50%) translateY(-50%) scale(1);
}
/* Effect 18: cross */
.cl-effect-18 {
position: relative;
z-index: 1;
}
.cl-effect-18 a {
padding: 0 5px;
color: #b4770d;
font-weight: 700;
-webkit-transition: color 0.3s;
-moz-transition: color 0.3s;
transition: color 0.3s;
}
.cl-effect-18 a::before,
.cl-effect-18 a::after {
position: absolute;
width: 100%;
left: 0;
top: 50%;
height: 2px;
margin-top: -1px;
background: #0072C6;
content: '';
z-index: -1;
-webkit-transition: -webkit-transform 0.3s, opacity 0.3s;
-moz-transition: -moz-transform 0.3s, opacity 0.3s;
transition: transform 0.3s, opacity 0.3s;
pointer-events: none;
}
.cl-effect-18 a::before {
-webkit-transform: translateY(-20px);
-moz-transform: translateY(-20px);
transform: translateY(-20px);
}
.cl-effect-18 a::after {
-webkit-transform: translateY(20px);
-moz-transform: translateY(20px);
transform: translateY(20px);
}
.cl-effect-18 a:hover,
.cl-effect-18 a:focus {
color: #fff;
}
.cl-effect-18 a:hover::before,
.cl-effect-18 a:hover::after,
.cl-effect-18 a:focus::before,
.cl-effect-18 a:focus::after {
opacity: 0.7;
}
.cl-effect-18 a:hover::before,
.cl-effect-18 a:focus::before {
-webkit-transform: rotate(45deg);
-moz-transform: rotate(45deg);
transform: rotate(45deg);
}
.cl-effect-18 a:hover::after,
.cl-effect-18 a:focus::after {
-webkit-transform: rotate(-45deg);
-moz-transform: rotate(-45deg);
transform: rotate(-45deg);
}
/* Effect 19: cross */
.cl-effect-19 {
position: relative;
z-index: 1;
}
.cl-effect-19 a {
padding: 0 5px;
color: #b4770d;
font-weight: 700;
-webkit-transition: color 0.3s;
-moz-transition: color 0.3s;
transition: color 0.3s;
}
.cl-effect-19 a::before,
.cl-effect-19 a::after {
position: absolute;
width: 100%;
left: 0;
top: 50%;
height: 2px;
margin-top: -1px;
background: #0072C6;
content: '';
z-index: -1;
-webkit-transition: -webkit-transform 0.3s, opacity 0.3s;
-moz-transition: -moz-transform 0.3s, opacity 0.3s;
transition: transform 0.3s, opacity 0.3s;
pointer-events: none;
}
.cl-effect-19 a::before {
-webkit-transform: translateY(-20px);
-moz-transform: translateY(-20px);
transform: translateY(-15px);
}
.cl-effect-19 a::after {
-webkit-transform: translateY(20px);
-moz-transform: translateY(20px);
transform: translateY(15px);
}
.cl-effect-19 a:hover,
.cl-effect-19 a:focus {
color: #fff;
}
.cl-effect-19 a:hover::before,
.cl-effect-19 a:hover::after,
.cl-effect-19 a:focus::before,
.cl-effect-19 a:focus::after {
opacity: 0.7;
}
.cl-effect-19 a:hover::before,
.cl-effect-19 a:focus::before {
-webkit-transform: rotate(45deg);
-moz-transform: rotate(45deg);
transform: rotate(90deg);	
}
.cl-effect-19 a:hover::after,
.cl-effect-19 a:focus::after {
-webkit-transform: rotate(-45deg);
-moz-transform: rotate(-45deg);
transform: rotate(-90deg);	
}

I hope you had joy of this and please drop a comment if you have any question!

/ Christian

Customizing SharePoint 2013 global navigation with CSS and jQuery – Part 3

In this third post, I will show how you can spice up the global navigation by add some CSS3. If you ever wanted to add some of the new CSS3 attributes like box-shadow or transitions to make some cool effects like animations this is a post for you. Now let’s change the look & feel for the global navigation in SharePoint Server to your heart’s desire!

GlobalNavIII

This example is suitable for SharePoint Server onprem as well as for SharePoint Online. The navigation is built after a structured navigation, there’s no CSS to handle dropdowns. The following CSS code includes transitions, an animation effect that let an element gradually change from one style to another. With this technique you can give the navigation an extra layer of interactivity.

There’s a bunch of sites out there like CSS Deck, CSS-trick, SpeckyBoy, Smashing Magazine etc. where you can find snippets and tutorial to get going with the latest stuff on HTML 5 and CSS 3. Why not find an example and try to implement this in SharePoint. In this post I’ll show you how to take one of this example and modify this a bit to fit it into SharePoint’s markup. Take a look at this example: http://cssdeck.com/labs/large-pressable-css3-navigation now let’s implement this one!

First of all, let’s wrap the SharePoint:AspMenu with a nav tag. Open your custom master and just add this two lines, start and end using the new HTML5 tag (nav) or an old good div if you prefer.

<SharePoint:AjaxDelta id="DeltaTopNavigation" BlockElement="true" CssClass="ms-displayInline ms-core-navigation" role="navigation" runat="server">
<SharePoint:DelegateControl runat="server" ControlId="TopNavigationDataSource" Id="topNavigationDelegate">
<Template_Controls>
<asp:SiteMapDataSource ShowStartingNode="False" SiteMapProvider="SPNavigationProvider" id="topSiteMap" runat="server" StartingNodeUrl="sid:1002"/>
</Template_Controls>
</SharePoint:DelegateControl>
<asp:ContentPlaceHolder id="PlaceHolderTopNavBar" runat="server">
<nav id="nav">
<SharePoint:AspMenu ID="TopNavigationMenu" Runat="server" EnableViewState="false" DataSourceID="topSiteMap" AccessKey="<%$Resources:wss,navigation_accesskey%>" UseSimpleRendering="true" UseSeparateCss="false" Orientation="Horizontal" StaticDisplayLevels="2" AdjustForShowStartingNode="true" MaximumDynamicDisplayLevels="2" SkipLinkText="" />
</nav>
</asp:ContentPlaceHolder>
</SharePoint:AjaxDelta>

And at last it’s time for the CSS:

.ms-core-navigation .ms-core-listMenu-horizontalBox li.static >  .ms-core-listMenu-item{
margin-right:1px
}
.ms-core-navigation .ms-core-listMenu-horizontalBox ul.static > li.selected > a > span > span{
color:#CFE1F1
}
#pageTitle{
display:none
}
#nav {
margin:4px auto;
overflow:hidden;
opacity:0.90;
border-radius:5px;
list-style-type:none;
}
#nav ul {
background-color:#2C4A70;
padding:0px 0px 1px 0px;
border-radius:5px;
}
#nav ul li {
height:55px;
}
#nav ul li a {
font:21px/52px Arial, Helvetica, sans-serif;
background-color: #0f6fb2;
background-image: -webkit-gradient(linear, left top, left bottom, from(rgb(15, 111, 178)), to(rgb(34, 65, 112)));
background-image: -webkit-linear-gradient(top, rgb(15, 111, 178), rgb(34, 65, 112));
background-image: -moz-linear-gradient(top, rgb(15, 111, 178), rgb(34, 65, 112));
background-image: -o-linear-gradient(top, rgb(15, 111, 178), rgb(34, 65, 112));
background-image: -ms-linear-gradient(top, rgb(15, 111, 178), rgb(34, 65, 112));
background-image: linear-gradient(top, rgb(15, 111, 178), rgb(34, 65, 112));
filter: progid:DXImageTransform.Microsoft.gradient(GradientType=0,StartColorStr='#0f6fb2', EndColorStr='#224170');
color: #fff;
text-decoration: none;
box-shadow:inset 0 1px 0 #0081bd,inset 0 2px 0 #0078b0,inset 0 3px 0 #0070a3, 0 0 10px rgba(0,0,0,0.2);
box-sizing:border-box;
transition:all .2s ease-in;
-o-transition:all .2s ease-in;
-moz-transition:all .2s ease-in;
-webkit-transition:all .2s ease-in;
}
#nav ul li a {width: 140px}
#nav ul li:first-child a {
-webkit-border-top-left-radius: 5px;
-webkit-border-bottom-left-radius: 5px;
-moz-border-radius-topleft: 5px;
-moz-border-radius-bottomleft: 5px;
border-top-left-radius: 5px;
border-bottom-left-radius: 5px;
}
#nav ul li:last-child a {
-webkit-border-top-right-radius: 5px;
-webkit-border-bottom-right-radius: 5px;
-moz-border-radius-topright: 5px;
-moz-border-radius-bottomright: 5px;
border-top-right-radius: 5px;
border-bottom-right-radius: 5px;
}#nav ul li a:hover {
box-shadow:inset 0 1px 0 #0070a3,inset 0 0 30px 0 #142a4a;
text-shadow:0 1px 3px #143157;
border-bottom:5px solid #0e223d;
}
#nav ul li a span {
border-left:1px solid #143157;
border-right:1px solid #1563a3;
height:100%;
display:block;
text-align:center;
box-sizing:border-box;
}
#nav ul li:first-child a span { border-left: none}
#nav ul li:last-child a span { border-right: none}

Please drop a comment if you have any questions

/ Christian

Follow

Get every new post delivered to your Inbox.

Join 1,281 other followers