Me & My SharePoint [FrontEnd]

© Christian Stahl – All about SharePoint branding & customizations

Getting started with REST in SharePoint 2013 – Part VI — October 30, 2014

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 — September 28, 2014

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 Continue reading

Getting started with REST in SharePoint 2013 – Part IV — August 31, 2014

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!

How to include a DVWP into a master page in the form of a UserControl — March 29, 2013

How to include a DVWP into a master page in the form of a UserControl

If you the data view web part is one of your tools, you might come across the need to embed a DVWP into a master page. You can do that as long as you make the DVWP reusable all over the site collection if we talking about a DVWP that fetch content from a list at one of the sites in the collection. However, the downside doing that, is that the DVWP will give a lot of extra markup, HTML and XSLT in your master page. Dealing with that makes the master page be a bit harder for further development and for maintain. Optionally you can looking into use a Content Editor in the master page where you link it to a text file containing your DVWP.

However, if you have created a DVWP and just want to include a single reference line link an include file in the master page to the DVWP instead of having the DVWP direct in your master page you can do that with help of Visual Studio. It’s just to create a User Control (UC) and host the DVWP in the UC file and deploy the file to SharePoint file system. When you do that it’s just to include the UC as an include file in the master page.

In the example I’ve created a link list named TopLinkList in the root site of the site collection with one extra column named SortOrder by the type choice where I have set the value 1 up to 5. The idea behind this is to include a set of links from the list in the master page that displays in the header of the pages.

LinkList1

Let’s try this out!

  1. Create the TopLinkList list and the extra column as described above and create let’s say three Items in this list
  2. Create a DVWP and the HTML & CSS that reads and display the list items. Don’t forget to make the DVWP available to all sites in the site collection. You can download my example and use it as an starting point for your further development. See the link at the end of the post
  3. Open your developer environment where you got SharePoint and in this example Visual Studio 2010 installed
  4. Open VS 2010 and create a new project by the type ’Empty SharePoint Project’
  5. Give it the name CustomTopLinks and click OK
  6. Select Deploy as a farm solution and click Finish
  7. In the solution explorer, right click at the project and select Add and then New Item
  8. Select User Control
  9. Name it TopLinks.ascx and click the button Add
  10. Copy the code from the DVWP and paste this just below the register tags and save the page
  11. In the solution explorer, right click at the project and select Build
  12. In the solution explorer, right click at the project and select Deploy. Verify that you got no errors
  13. When this is done, open your custom master page with SharePoint Designer
  14. Add the following register tag at the top of the page:
    <%@ Register TagPrefix="CustomTopLinks" TagName="CustomTopLinks" Src="~/_controltemplates/CustomTopLinks/TopLinks.ascx" %>
    
  15. Add the control somewhere in your markup where you like it to appear in the pages:
    <CustomTopLinks:CustomTopLinks id="CustomTopLinks" runat="server"/>
    
  16. Done!

Download the DVWP taken from this example

Take a look at the following image that shows the columns you’ll need

LinkList2

</ Christian>

Comment functionality for news pages – Part II — July 18, 2012

Comment functionality for news pages – Part II

This article is the last one of two describing how to implement comment functionality into the news pages in SharePoint Server 2010. You’ll find Part I here. If you followed the examples in the Part II and have implemented the comment functionality it’s time to create one or more news rollup web part:

  • A web part that display the latest news pages and the number of related comments
  • A web part that display recently commented news pages
  • A web part that display the Display most commented news pages

First step – create a news rollup DVWP

When Lists and libraries are connected with a lookup you have the possibility to join content from both sources into a single Data View Web Part (joined sub view). This is useful if you want to create a news rollup that shows the latest news including the number of comments for each news item. In my examples I use the Page library in the root like the custom list NewsComments. You can use this in a sub site for news if you prefer.
I wanted to strip out HTML from the body text and limited body text by a number of words, so I used the strip HTML and the Count Word templates; a Codeplex project called SPXSLT created by my friend Marc D Anderson.

  • Open SPD and create a new folder direct in the root level and give it the name ’SPD-WebParts’.
  • Create a new ASPX page and give it the name RollupNews.aspx, check it out and open this with SPD.
  • Paste all the content from my file with the same name, you’ll find the download link at the end of this blog post.
  • Save the file and hit F12 for preview.
  • Check in and publish the file.
  • You can save this DVWP to the site gallery or to your disc if you want to implement the web part with the browser.

Next step – create a recently comments DVWP

This web part displays the most recent commented news pages. If the comment is created today, ‘New!’ will be displayed otherwise not.

  • Create a new ASPX page, save into the folder SPD-WebParts and give it the name LatestCommentedNews.aspx, check it out and open it up.
  • Paste all the content from my file with the same name, you’ll find the download link at the end of this blog post.
  • Save the file and hit F12 for preview. Check in and publish the file.
  • You can save this DVWP to the site gallery or to your disc if you want to implement the web part with the browser.

Next step – create a most comments DVWP

This web part display the most commented news pages. In order to group this, I have used the PageID column for the grouping. Furthermore I want to sort the web part by number of Items but of some reason I haven’t yet found the perfect way to accomplish this in XSLT, so I leave this as an open question to you readers! If you found a pure XSLT way for this I’ll update this blog post. In the meantime I’ll go for the jQuery TableSorter plugin. This plug is useful in different scenarios when you need client side sorting with all kind of data and it a works great if you need secondary ‘hidden’ sorting or for example just sorting a table without page refresh. You’ll find the file included in the download, see the link at the end of this blog post.

  • Create a new ASPX page, save it save into the folder SPD-WebParts and give it the name MostCommentedNews.aspx, check it out and open it up.
  • Paste all the content from my file with the same name, you’ll find the download link at the end of this blog post.
  • Save the file and hit F12 for preview. Check in and publish the file.
  • You can save this DVWP to the site gallery or to your disc if you want to implement the web part with the browser.

To activate the sort order, add a reference in your custom master page to the tablesorter file and add the following line of script into an external JS file or into the head section of your master page:

<script type="text/javascript">
$(document).ready(function() {
// Custom sort DVWP news sort by most comments
$('.tablesorter').tablesorter({sortList:[[0,0]] });
});
</script>

Download the files

If you got questions about this or maybe ideas for more functions or web parts related to this, pleas drop a comment.
Download my example files here

Thanks!
/ C

Comment functionality for news pages – Part I — June 30, 2012

Comment functionality for news pages – Part I

If you want to implement comment functionality into the news pages in SharePoint Server 2010, a no code solution with Data Views and portion of jQuery could be a perfect option for you. Alternative you can use the OOTB Note board web part or even use a blog site to get comment functionality but these options limits you if you need to customize such solution in comparison to data views powered with XSLT, jQuery and CSS.

My concept for this is basically to use two connected lists. In the following example I’ll use the Page library in the root site and a custom list called NewsComments. The NewsComments lists have a lookup column (PageID) that connects the ID column in the Pages library. You can do this at a news sub site as well if you prefer.
I am using a data view form web part for the comment textbox in a page layout that sends the comment text, the current page ID, the page title and the page URL to the NewsComments list. Into this Page layout that serves as a template for the news pages, I have created a DVWP that displays all comments related to the current page. Do get this relation I use a parameter with a server variable and a XSL filter that matches current page name to the column in NewsComments list that stores the page names. I do also use some jQuery to grab and populate information on the page and the list.
When you connecting lists with a lookup it gives you the possibility to join content from both lists in a Data View Web Part (joined subview), this can also be useful if you want to create a news rollup that shows the latest news including the number of comments per news item. I’ll write more about such web parts in the next blog.

First step – create the list and a page layout

  • Create a list in the root site of the site collection by the type of Custom List named NewsComments. Create following columns:

    • A column named PageID by the type Lookup. Select Pages in ’Get information from’ and select ID for ’In this column’. Set it to required and click OK.
    • A column named PageTitle by the type Single Line of Text and click OK.
    • A column named Comments by the type multiple lines of text with 5 rows, specify this as Plain text and click OK.
  • Open SPD and create a new page layout and give it the name ’NewsPages’. Don’t forget to give the file a Title. You can copy an existing page layout. Open the page and add or remove the content fields you like the page to have, you can use just Page Content and Title. Add some additional markup; give the elements class names that the jQuery functions needs. Download my example files down below and copy the markup. In my example I have created a Page layout based on the Article Page layout, if you are using a content type like the Enterprise Wiki you have to add tag prefix in the top of the page layout that match the fields you put on the page.
  • Save and publish the file in _catalogs > masterpage folder at the root site. Make sure that it’s available at the root site as a selectable page layout so you can specify this page layout when you create a new page in the root site.
  • Now use the browser and create some pages at the root site, for example name the first on to test1 and the URL will be /Pages/test1.aspx. Use your new page layout as template.

Next step – create a comment in the list

Open the NewsComments list and create a new item, type the URL name of one of the pages you have created in the tile field, for example test1.aspx. Type the filename of the page in the Title field, select the ID of this page, type the title of the page in the PageTitle column and create a comment. You’ll need to do this just to make sure the comments can be connected.

You have now created the basics and were now move the two DVWPs that will display the comments for the pages and make the comment box available. Download my example files if you get stuck, you can just copy the DVWPs and the jQuery and paste them in your page layout.

Next step – create a Data View Web Part that only display comments related to the current news page.

  • Open SPD and the page layout that you just created with SharePoint Designer. Create a DVWP (display Item Form) that get the information from the NewsComments list. Add this DVWP at the bottom of the page just below the last content field. Use no paging, show all objects and show only the column Comments.
  • Create a new parameter as in the image below. The parameter is required to match the current page’s URL name to what caught up in NewsComments list’s Title field.
  • Change the dsQueryRespoinse/Rows variable. If you have a language other than English don’t forget to change name of Pages. Locate the following line:

    <xsl:variable name="Rows" select="/dsQueryResponse/Rows/Row"/>
    

    change to:

    <xsl:variable name="Rows" select="/dsQueryResponse/Rows/Row[@Title=substring-after($ReferPageURL, 'Pages/')]"/>
    
  • Save the page and verify that only the comments appear per page according to what you entered in the NewsComments list.
  • Clean up the DVWP, och add the some markup for presentation.
  • Verify that everything works so far.

Next step – create a form web part

  • Add a DFWP (New Item Form) below the other data view, that get the information from the NewsComments list.
  • Use only following columns: PageID, PageTitle, Title and Comments

Clean the DFWP and give it some markup. As for the other DVWP, it’s important that you use the appropriate markup when jQuery and CSS makes use of class names.

Next step – create the jQuery you need for the comment box in the page layout

The purpose of the following jQuery is to get the page’s ID populated in the dropdown and to populate the Page’s title and URL into the select fields. I have also included a function that show characters left and set a limit to 140 characters.

<script type="text/javascript">
// Limit characters
function limitChars(textid, limit, infodiv){
var text = $('#'+textid).val();    
var textlength = text.length;
if(textlength > limit) {
$('#' + infodiv).html(''+limit+' limit reached');
$('#'+textid).val(text.substr(0,limit));
return false;
}
else {
$('#' + infodiv).html(''+ (limit - textlength) +' characters left');
return true;
}}
$(function(){
$(".FormFieldNewsComments > span > textarea[title='Comments']").keyup(function(){
limitChars(".FormFieldNewsComments > span > textarea[title='Comments']", 140, "LimitInfo");
})
});
	
$(document).ready(function() {
var loc = window.location.href.substr(window.location.href.lastIndexOf("/")+1); // Get the page filename
var PageTitle = $('.PageTitleDiv').html(); // Get the page title
$(".FormFieldNewsTitle > span > input[title='Title']").val(loc); // insert page filename in a CSS hidden formfield
$(".FormFieldPageTitle > span > input[title='PageTitle']").val(PageTitle);	// insert pages title in a CSS hidden formfield
var HiddenInput = $("input[title='PageID']").attr("optHid"); // Lagrar ID till attributet optHid
$("select[title='PageID']").val(_spPageContextInfo.pageItemId); // If less than 20 items i Pages bibl, lägger in ID nr som en selected i DD
$("input[title='PageID']").val(_spPageContextInfo.pageItemId);  // If 20 or more items in Pages lib
$("input[id='" + HiddenInput +"']").attr("value",(_spPageContextInfo.pageItemId)) // Set ID as selected if 20 or more items in Pages lib
});
</script>

Next step – add a few more functions

I added a few additional functions in this example which I think may be helpful and that is the ability to remove own comments and to show number of comments for the page. If you download my example files, this is already included in the DVWPs.

Show the number of comments

<xsl:if test="count($Rows) = 0">No comments yet..</xsl:if>
<xsl:if test="count($Rows) = 1"><xsl:value-of select="$dvt_RowCount" /> Comment</xsl:if>
<xsl:if test="count($Rows) &gt;= 2"><xsl:value-of select="$dvt_RowCount" /> Comments</xsl:if>

Add the following parameter to your XSL style sheet

<xsl:param name="UserID" />

Create these parameter for the rowview template

<xsl:param name="KeyField">ID</xsl:param>
<xsl:param name="KeyValue" select="ddwrt:EscapeDelims(string(@ID))"/>
<xsl:param name="Mode">view</xsl:param>

Match the author to the logged in user

<xsl:if test="@Author.title = $UserID">
<a href="javascript: {ddwrt:GenFireServerEvent(concat('__cancel;__delete={',$KeyField,'=',$KeyValue,'};__commit'))}">DELETE</a>
</xsl:if>

If you want to create a link to the comment list that only administrators should see you can use the DDWRT:IfHasRights() function with an appropriate value

<xsl:if test="ddwrt:IfHasRights(33554432)"><a href="/Lists/NewsComments/AllItems.aspx"><img src="/Style Library/Branding/Images/EditIcon.gif" alt="" /></a></xsl:if>

Next step – branding

The functions for this are now completed and it’s time to give this some visual awesomeness! Download my example files where you find CSS and an image that should get you going.

More to do

There are a lot of things to keep in mind to get this up and I hope you can take this as a base for your own solution and find inspiration. There are many ways to extend this and maybe I’ll publish this to Codeplex for the support and possibilities to further extensions. Maybe it could be an idea to integrate this function with my friend Marc D Anderson’s SPservices SocialDataServices

Download the files

Download my example files here

Part II

In the next blog I’ll show you how to create a news rollup out of this, a joined DVWP that displays the latest news and the number of related comments.

Customize the UI of web parts in SharePoint 2010 — January 27, 2012

Customize the UI of web parts in SharePoint 2010

This post describes how to customize a standard Web Part in SharePoint by using SharePoint Designer 2010. Depending of the look and feel or factors such as accessibility, performance or cross browser stability it could be a challenge to bend the web part UI exactly in the way you want. The markup of the web parts in SharePoint contains a quite deep nested table structure and the elements do not always have an id or class.

When you need to create an advanced design for the web parts, the alternatives is to manipulate the DOM with jQuery or create custom web part control wrappers with code. Besides of this, CSS 3 comes with some interesting possibilities like box shadow and border radius that lets you create stuff like boxes with curved corners but it’s not an option here because we need to render the master page in IE8 mode to get all functionalities intact in SharePoint 2010.

So what can you do quick and easily then? The web part headers and all the cells in header row can easily be customized with CSS just like the borders around. I have made four examples with different colors you can download and use at the bottom of this page.

Using only CSS and images for rounded corners is the easiest approach where you don’t need plugins like CSS3 Pie or other htc solutions, fallback methods for different browsers or care about slow rendering when rewriting the already complex and nestled DOM. But when you reach the border of what is possible to do with just CSS and images it’s time to bend the DOM with our friend jQuery or fire up Visual Studio for write a control adapter. Take a look at this blog post from ‘All things SharePoint’ that describes how to use jQuery to adding classes and wrappers into the DOM so you can get a wrapper with rounded corners for the web parts, and take a look at Waldek Mastykars post about how to removing the web part tables with code.

Back to the basics, let’s see how you can customize the web part headers the easy way.
The following example, see the image above, applies background images for the corners and for the middle section. The left and right corners have dimensions of 7 x 33 pixels, and the middle image has dimensions of 14 x 33 pixels.

Let’s go

Download the images and put them into Style Library/BlogBranding/Images or change the path in the CSS below if you want to put the images in some other folder.

/* WebPart headers */
/* All tdS in the row */
.ms-WPHeader > TD{
background-image: url('/Style Library/BlogBranding/Images/WP-MidGreen.png');
background-repeat:repeat-x; 
padding-left:1px; padding-right:1px; height:33px;
border-bottom-style:none!important;border-bottom-color:inherit!important; border-bottom-width:0px!important;
}
/* Left cell */
.ms-WPHeader td:first-child {
width:5px;
background-image:url('/Style Library/BlogBranding/Images/WP-LeftGreen.png')!important;
background-repeat:no-repeat;
}
/* Right cell */
.ms-wpTdSpace {
width:7px;
background-image:url('/Style Library/BlogBranding/Images/WP-RightGreen.png')!important;
background-repeat:no-repeat;
background-color:transparent;
}
/* Arrow */
.ms-WPHeaderTdMenu{
background-color:transparent;
border:0px!important;
}
/* Web part title */
.ms-WPTitle {
padding-left:10px;
font-family:Arial, Helvetica, sans-serif;
color:#fff;
font-weight:bold;
margin-bottom:1px;
font-size:14px;
}
/* linked title and visited */
.ms-WPTitle a, .ms-WPTitle a:visited {
color:#fff;
text-decoration:none;
}
/* hover title */
.ms-WPTitle a:hover {
color:#333;
text-decoration:none;
}
/* hover web part menu */
.ms-WPHeaderTdMenu:hover{
border-left:1px solid transparent;
background-image: url('/Style Library/BlogBranding/Images/WP-MidGreen.png');
}

More stuff you can do

If you want to do something special just for one single web part based on some condition or similar? Let’s say you want to have a different look and feel for some web part only if its header text is ‘Links’. I made up an example that makes the header title red and adds a border with a dropshadow filter older IEs and BoxShadow for modern browsers. Other web parts will not apply this look and feel.

Here’s the jQuery

$(document).ready(function() { 
var WPtitle = $('.ms-WPTitle span'); 
for (var i = 0; i <= WPtitle.length; i++) { 
	if ($(WPtitle[i]).text() == 'Links') { 
            $(WPtitle[i]).css({'color': 'red'}); 
           	$(WPtitle[i]).parents().eq(10).addClass("WebPartBorder");
	}
	else if ($(WPtitle[i]).text() == 'Shared Documents') { 
            $(WPtitle[i]).css({'color': 'blue'}); 
	} 
} 
});

Here’s the CSS

/* All TDs in the table row */
.ms-WPHeader TD{
background-color: #f7f7f7;
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ebebeb', endColorstr='#e2e2e2');
background: -webkit-gradient(linear, left top, left bottom, from(#e2e2e2), to(#ebebeb));
background: -moz-linear-gradient(top, #e2e2e2, #ebebeb);
border-top:1px #cfcfcf solid; border-bottom:1px #e2e2e2 solid!important;
padding:3px;
}
/* for css / jquery drop shadow */
.WebPartBorder{
border:1px #777 solid!important;
-moz-box-shadow: 5px 5px 5px #ccc;
-webkit-box-shadow: 5px 5px 5px #ccc;
box-shadow: 5px 5px 5px #ccc;/* CSS3 */
background-color:#fff;
filter: progid:DXImageTransform.Microsoft.DropShadow(OffX=5, OffY=5, Color=#e9e9e9);    
}
.WebPartBorder > tbody {
background-color:#f7f7f7!important
}
/* Border to the sides */
.ms-WPHeader td:first-child {
border-left:1px #e2e2e2 solid;
border-right:0px;
}
.ms-wpTdSpace {
border-right:1px #e2e2e2 solid;
}
/* Web part title */
.ms-WPTitle {
color: #333;
font-weight:bold;
}
/* linked title and visited */
.ms-WPTitle a, .ms-WPTitle a:visited {
color: #333!important;
text-decoration:none!important;
}
/* hover title */
.ms-WPTitle a:hover {
color:#0072bc!important;
}
/* hover web part menu */
.ms-WPHeaderTdMenu:hover{
 background-image:none;
border-top:1px solid #ccc;
border-right:1px solid transparent;
border-left:1px solid transparent;
background-color:#f7f7f7;
}
/* for the jQuery */
.LinkTextColor {
color:red;
}

Hopes this gives you some ideas, and please feel free to drop a comment!

/ Christian