Me & My SharePoint [FrontEnd]

© Christian Stahl – All about SharePoint branding & customizations

Add an arrow to the global navigation in SharePoint 2010 — January 31, 2013

Add an arrow to the global navigation in SharePoint 2010

Sometimes it’s the small details that matters most and makes the difference. This post is about how to customize the look and feel for the global navigation, one important element in the SharePoint interface. The navigation control renders a fairly deep HTML structure with a lot of classes to keep in mind when you need to set your branding on the top of it. Recently I built an Intranet branding where the agency had the desire to include a small arrow for selected links in the navigation. This CSS do also take care of drop downs, in the case you are using that. I hope this could be useful for you if you need to include graphics, like this arrow in the global navigation.

ZeroOne

CSS

a:focus, a:active, a:hover {outline:none}
#s4-topheader2 {
border-bottom:0px transparent solid!important
}
.s4-tn {
background-color:#000; border-bottom:#fff 1px solid;
font-family:"Trebuchet MS"
}
.menu-horizontal {
margin-left:12px; border-left:#000 1px solid;
border-right:#000 1px solid;
}
.s4-tn ul.static > li.static > .menu-item {
height:26px; line-height:26px;
border-left:transparent 1px solid;
border-right:transparent 1px solid;
padding-left:15px; padding-right:15px;
white-space:nowrap; color: #fff;
font-size:12px; font-weight:bold;
}
.s4-tn ul.root > li.static > ul.static > li.selected {
background-color:#0089C5;
}
.s4-toplinks .s4-tn a.selected {
border: 1px solid transparent; margin: 0px;
padding-left:15px; padding-right:15px;
color:#fff; line-height:16px!important;
position:relative; z-index:10; left:0px; top:5px;
background: url('/Style%20Library/Images/MenuDownArrow.png') no-repeat center 30px !important;
}
.s4-tn ul.static > li.static > a:hover {
background-image:none; background-color:#0089C5;
border-left:transparent 1px solid; border-right:#transparent 1px solid;
color:#fff!important; text-decoration:none;
}
.menu-horizontal ul.dynamic a.dynamic-children span.additional-background {
padding-right:0px;
}
.menu-horizontal a.dynamic-children span.additional-background {
background-image:none; padding-right:0px;
}
.s4-tn ul.dynamic {
background-image:none;
border-top:0px; border-right:0;
border-bottom:1px #ccc solid; border-left:1px #ccc solid ;
margin:0px; margin-left:1px;
}
.s4-tn li.dynamic {
background-image:none;
border-top:1px #ccc solid; border-right:1px #ccc solid;
border-bottom:1px #fff solid; border-left:1px #fff solid;
}
.s4-tn li.dynamic > .menu-item {
height:16px; padding:7px 10px;
color:#333; background-color:#f7f7f7;
}
.s4-tn li.dynamic > a:hover {
color:#00557B; background-color:#fff;
}
.dynamic > li.dynamic-children > ul.dynamic {
margin-left:-2px; margin-top:0px;
}

Download the small arrow from here

I’ve written a few blog posts earlier about the global navigation. You can found the posts here.

If you have any questions about this, please feel free to contact me.

/ Christian

User information in SharePoint 2010 with help of the SPCWC control — December 21, 2012

User information in SharePoint 2010 with help of the SPCWC control

In this post I’ll show you how you can retrieve something from the current user’s profile and then do something based of its value with a little help of jQuery and CSS. In this example I have used a typical AD field (office) that are imported into SharePoint’s profile information. You can use any field that exist as a property in the profile information like Country, manager, profile picture or even use a custom property in SharePoint.

workingInLondon

Let’s say we want display something at the Intranet for those users that works in London and display some other stuff for the one’s that works in Paris. This can be used in a many different scenarios, hide/show web parts, controls or fields in the page layout or maybe set a cookie based on the value or do something related to the branding, redirect users to different pages and much more. Hopes this example gives you some ideas for a cool implementation of your own!

Let’s try this out

Use SharePoint Designer 2010 and open the custom master page, your custom CSS file and your JS file.

Masterpage
First you need to declare SPCWC tag prefix in your custom master page. It’s just to include the following line for example just below the last existing tag prefix

<%@ Register Tagprefix="SPSWC" Namespace="Microsoft.SharePoint.Portal.WebControls" Assembly="Microsoft.SharePoint.Portal, Version=14.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>

Then you need to load and make the profile properties available through the pages that are connected to your custom master page. This attribute is needed for some of the properties, but in this example you don’t need it. You can for example paste the following tag just below the existing WebPartPages:SPWebPartManager tag.

<SPSWC:ProfilePropertyLoader id="m_objLoader" LoadFullProfileOfCurrentUser="true" runat="server"/>

Finally it’s time to include the HTML somewhere in your custom master page including the profile property value.

<div class="Office">
<SPSWC:ProfilePropertyValue PropertyName="Office" ApplyFormatting="false" runat="server"/>
</div>
<div class="OfficeOutput IfOffice s4-notdlg"></div>

jQuery
Add the following script in an external JS file referenced from your master page.

$(document).ready(function(){	
var office = $('.Office > span').text();
if(office == 'Stockholm') {
$(".OfficeOutput").show().html('Working in Stockholm!');
}
else if(office == 'London') {
$(".OfficeOutput").show().html('Working in London!');
}
else {
// do something else
} 
});

CSS
Add the following CSS in an external CSS file referenced from your custom master page.

.Office > span{display:none}
.OfficeOutput{display:none}
.IfOffice{
padding:4px; background-color:#304F6D;
color:#fff; font-family:"Segoe UI"; font-size:8pt
}

That’s all, hopes this gives some ideas or inspiration. Please comment if you have questions or if just want to discuss this.
/ Christian

5 PowerShell snippets for SharePoint branders — October 31, 2012

5 PowerShell snippets for SharePoint branders

Just as I wrote in my last blog post I like to collect pieces of code snippets. Sooner or later I’ll found them useful and they could save time and other efforts. My intention with this post is just to share a couple of my snippets and I hope that you’ll found something useful here.

PowerShell is a command-line scripting tool that provides an administrator full access to applicable application programming interfaces (APIs), along with the ability to unlock the capability to interact directly with SharePoint 2010 Products to manipulate Web applications, site collections, sites, lists and much more. So what’s a useful thing to do with PowerShell as a SharePoint brander or a front end developer? Well, there are a lot of different types of tasks you can use PowerShell to, for example populate a list with a large amount of objects when you need to performance test your Data View Web Part or if you need to apply a theme to let’s say some site in the structure including its sub sites or if you need to batch update properties of a collection page layouts.

Maybe you see something that can be written more efficient or if you have some cool snippets of your own you like to share, please drop this in a comment. Take these snippets as they are, try them first in your developer or test environment and feel free to use them and modify in the way you want.

Running PowerShell scripts is easy and you will find many resources out there if you never used PowerShell before, when you know the basics it’s just to go ahead and try these out. This stuff is written for SharePoint 2010 but most of this can be used in SharePoint 2013 as it is.

1. Change Master Page for all sites in the collection

In this example I’ll apply a customer master to all the sites in the site collection, this can be rewritten specific for SharePoint foundation, where PowerShell is much useful for such task. In this snippet I have set V4.master, so have to change the name of the master page file if apply a custom master page.

# ----- For publishing sites and non publishing sites
$site = Get-SPSite http://intranet
foreach ($web in $site.AllWebs) {
$web; $web.CustomMasterUrl = "/_catalogs/masterpage/V4.master"; 
$web.Update(); $web.CustomMasterUrl;
$web.Dispose()
}
foreach ($web in $site.AllWebs) {
$web; $web.MasterUrl = "/_catalogs/masterpage/v4.master"; 
$web.Update(); $web.MasterUrl;
$web.Dispose()
}
$site.Dispose()
write-host "Complete! V4.master is now applied";

2. Set alternate CSS

In this way you can set a custom CSS file as an alternate CSS at the top site of your site collection, publishing sub sites will inherit the alternate CSS by default.

$web = Get-SPWeb http://intranet
$web.AlternateCssUrl = "/Style Library/MyStyles/main.css"
$web.AllProperties["__InheritsAlternateCssUrl"] = $True
$web.Update()

3. Set a site logo

With this one you can associate a logo with all sites in the site collection by entering the URL to an image file.

(get-spsite http://intranet).AllWebs | foreach {
$_.SiteLogoUrl = "/Style%20Library/MyClient/Images/ClientLogo.png";

4. Set regional setting/locale

This one can be handy when you need to specify the way the site displays numbers, dates, and time. In this example I set locale to Swedish (1053).

$site = Get-SPSite http://intranet
foreach ($web in $site.AllWebs) {
$web; $web.Locale = 1053; 
$web.Update(); $web.Locale;
$web.Dispose()
}
$site.Dispose() 

5. Set a theme

This one will set a theme to all sites in the site collection. This script is originally written by my friend MVP Yaroslav Pentsarskyy

$SiteUrl = "http://intranet"
$NewTheme = "Azure"
# Loading Microsoft.SharePoint.PowerShell 
$snapin = Get-PSSnapin | Where-Object {$_.Name -eq 'Microsoft.SharePoint.Powershell'}
if ($snapin -eq $null) {
Write-Host "Loading SharePoint Powershell Snapin"
Add-PSSnapin "Microsoft.SharePoint.Powershell"
}
# Setting site themes on sites and sub sites
$SPSite = Get-SPSite | Where-Object {$_.Url -eq $SiteUrl}
if($SPSite -ne $null) 
{
$themes = [Microsoft.SharePoint.Utilities.ThmxTheme]::GetManagedThemes($SiteUrl);
foreach ($theme in $themes) 
{ 
if ($theme.Name -eq $NewTheme) 
{ 
break; 
} 
} 
foreach ($SPWeb in $SPSite.AllWebs)
{
$theme.ApplyTo($SPWeb, $true); 
Write-Host "Set" $NewTheme "at :" $SPWeb.Title "(" $SPWeb.Url ")"
}
}
Write-Host "Themes updated at:" $SPSite.Url -foregroundcolor Green

More

If you’re a truly SharePoint Designer guy, why not use PowerShell to check if you allowed to do your branding stuff before fire it up…

Get-SPDesignerSettings -webapplication http://intranet

There’s lot of blogs about using PowerShell in SharePoint but here’s a pic of a few cool scripts that somehow are related to this topic.

N8Design Stefan Bauer – Hide fields from list forms using PowerShell

MSDN Samples Stefan Bauer – version cleanup in SharePoint

Gary Lapointe – Reset Theme

Finally I’d like to give thanks to MVP Cathy Dew for inspiring discussions about this topic; PowerShell from a brander’s perspective as well as I’d like to thanks Falak Mahmood for general discussions and suggestions for the use of PowerShell.

Stay in tune!
Christian

10 jQuery snippets for SharePoint 2010 — September 27, 2012

10 jQuery snippets for SharePoint 2010

I like to collect pieces of code snippets, sooner or later I’ll found them useful and they could save time and other efforts. My intention with this post is just to share a couple of my snippets and I hope that you’ll found something useful here.

Maybe you see something that can be written more efficient or if you have some cool snippets of your own you like to share, please drop this in a comment. These snippets are all plugin independent and should be easy to follow and modify and they can be used in SharePoint Designer 2010, Visual Studio or be included in a text file in SharePoint linked from a content editor. Don’t forget to create a reference to latest jQuery in the master page or into the text file.

1. Text manipulation
In this example I replace ‘All site content’ with help of the each function.

/* --- Doc ready ---*/
$(document).ready(function() {
$('.ms-splinkbutton-text').each(function(i){ $(this).text($(this).text().replace('All Site Content','More stuff here..'))
})
})

2. Check the URL
If the URL contains ‘news’, let’s do something conditionally with JS.

if(document.URL.indexOf("news") != -1){ 
alert("News site"); 
} else{ 
alert("Not the news site"); 
}

Another way is to getting a URL parameter and maybe their values and to something based on a condition with help of jQuery. Let’s give the background different colors depending if the view are sorted by Desc or Asc

var url = window.location.href; 
/* --- Doc ready ---*/
$(document).ready(function() {
if (url.search("&SortDir=Asc") > 0) { 
$(".ms-viewheadertr").css('background-color','lime');
};
else if (url.search("&SortDir=Desc") > 0) { 
$(".ms-viewheadertr").css('background-color','yellow');
};
/* --- End doc ready ---*/
});

3. Timestamp
If each page you create needs to have a unique name, you can set a time stamp when it creates. In this example I’ve used year to milliseconds and a random number at the end. This may be useful for a news site with many pages.

// create a timestamp with random
var now = new Date();
var year = now.getFullYear();
var month = now.getMonth();
var day = now.getDay();
var hours = now.getHours();
var minutes = now.getMinutes();
var seconds = now.getSeconds();
var milliseconds = now.getMilliseconds();
var rand = Math.floor((Math.random()*1000000)+1);
var pageID = ('ID-')
var CustomInput = pageID + '' + year + '' + month + '' + day + '' + hours + '' + minutes + '' + seconds + '' + milliseconds + '' + rand;

/* --- Doc ready ---*/
$(document).ready(function() {
$("input[name='ctl00$PlaceHolderMain$nameInput']").val(CustomInput);
/* --- End doc ready ---*/
});

If you only want this function for let’s say a news site, you can use an If statement and identify the URL. But don’t forget that URL can be changed.

/* --- Doc ready ---*/
$(document).ready(function() {
if(document.URL.indexOf("news") != -1) { 
// Unique page title
$("input[name='ctl00$PlaceHolderMain$nameInput']").val(CustomInput);
} else{}
/* --- End doc ready ---*/
});

4. Change the attribute
Let’s say you want to change for example the title tag for the ‘I Like It’ button, you can do like this to set a custom attribute.

/* --- Doc ready ---*/
$(document).ready(function() {
$(".ms-socialNotif-Container > a").attr({
title: "Click the button if you like this page",
}); 
/* --- End doc ready ---*/
});

5. Change CSS
Let’s change the header text to red if the name is Link.

/* --- Doc ready ---*/
$(document).ready(function() {
$(".ms-WPTitle span:contains('Links')").css("color", "red"); 
});

Another way is to use a condition and a variable for this, if the web part header is equal to Shared Documents set the color to green, if the text is eq to Link set a border around the web part and set the text to red color. Normally I set the CSS into a CSS file, and you can use addClass to set the class as an option to set the CSS inline the script if you like.

/* --- Doc ready ---*/
$(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).css({'border': '1px black solid!important'});
}
else if ($(WPtitle[i]).text() == 'Shared Documents') { 
$(WPtitle[i]).css({'color': 'green'}); 
}} 
/* --- End doc ready ---*/
});

6. Add expand / collapse web parts
The following code will get expand/collapse for all standard web parts.

/* --- Doc ready ---*/
$(document).ready(function() {
$(function($) { 
$('.s4-wpTopTable').find('tr:first h3').append('<a class=\'min\' style=\'float:left; margin-right:5px\'><img src=\'/_layouts/images/collapse.gif\'/></a>'); 
var Collapse = "/_layouts/images/collapse.gif"; 
var Expand = "/_layouts/images/expand.gif"; 
$('.min').click(function(){      
var img = $(this).children(); 
$(this).closest('.s4-wpTopTable').find('tr:first').next().toggle().is(":visible") ? img.attr('src',Collapse) : img.attr('src',Expand ); 
}); 
});
});

7. Modify form field
jQuery can be used in many ways for standard list forms in SharePoint and this fist example shows how to set read only, a color and a specific width for the title field in edit mode.

/* --- Doc ready ---*/
$(document).ready(function() {
$("input[title='Title']").attr("readonly","true").css('background-color','#ccc').width(70);
/* --- End doc ready ---*/
});

Next example shows how to set a field limit and add a counter that shows number of characters left

// Show Nr of Characters left in a common list field
(function($){  
$.fn.fieldLimit = function(options) {  
return this.each(function() {  
var characters = 30;
$(this).keyup(function(){
if($(this).val().length > characters){
$(this).val($(this).val().substr(0, characters));
}	
var remaining = characters - $(this).val().length;
$(options.result).html(remaining + " characters left");			
});
});  
};  
})(jQuery);

/* --- Doc ready ---*/
$(document).ready(function() {
$('.ms-formtable').prepend("<div class='CharactersLeft'></div>");
$('input[title$=Title]').fieldLimit({
result:".CharactersLeft",
});
/* --- End doc ready ---*/
});

8. Check site template
If you need to do something based on which site template a site has been created from, you can identify this with help of the site template ID. I have only covered a few templates below.

/* --- Doc ready ---*/
$(document).ready(function(){
CurrentTemplate = g_wsaSiteTemplateId;
TeamSite = 'STS#0'
EnterpriseWiki = 'ENTERWIKI#0';
PublishingSite = 'CMSPUBLISHING#0';
if (CurrentTemplate == TeamSite){
alert('Im a Team site');}
else if (CurrentTemplate == EnterpriseWiki){
alert('Im a Enterprise Wiki');}
else if (CurrentTemplate == PublishingSite){
alert('Im a Publishing Site');}
else {
alert('Sitetemplate not defined yet..');}
/* --- End doc ready ---*/
});

9. Welcome message
This example shows how to work with variables. You’ll also find some plain old good JS date stuff that can be useful when you need to check times.

/* --- Doc ready ---*/
$(document).ready(function(){
var WelcomeMenuContent = $('.ms-welcomeMenu > a.ms-menu-a > span');
var UserName = WelcomeMenuContent.text();
var FirstName = UserName.split(" ")[0];
var Display;
var Digital = new Date()
var Hours = Digital.getHours()
Morning = 'Good morning' + " " + FirstName;
Lunch = 'Lunch time' + " " + FirstName;
Evening = 'Good evening' + " " + FirstName;
Night = 'Time to go home' + " " + FirstName;
TimeElse = 'Welcome' + " " + FirstName;
if (Hours >= 5 && Hours <= 11) 
WelcomeMenuContent.text(Morning);
else if (Hours == 12) 
WelcomeMenuContent.text(Lunch);
else if (Hours >= 13 && Hours <= 17) 
WelcomeMenuContent.text(Evening);
else if (Hours >= 18 && Hours <= 23) 
WelcomeMenuContent.text(Night);
else
WelcomeMenuContent.text(TimeElse);	
/* --- End doc ready ---*/
}); 

10. Append today’s date
While we’re talking about get date with JS, let’s see how you can use this to display current date somewhere at the page like this.

var d = new Date();
var month = d.getMonth();
var date = d.getDate();
var year = d.getFullYear();
/* --- Doc ready ---*/
$(document).ready(function() {
$('.s4-pagedescription').append("<div style='float:right'>" + month + "/" + date + "/" + year + "</div>"); 
});

Stay in tune!

/ Christian Ståhl

Use jQuery & cookies in SharePoint 2010 — August 31, 2012

Use jQuery & cookies in SharePoint 2010

In this article I’ll show you how to use Cookies in jQuery for your SharePoint Designer 2010 no code applications.

With help of a cookie you can write information to the user’s computer and this can be useful if you need to store stuff like visitors preferences, for example if the user has checked a check box or not at some page. Cookies can be very useful in many ways, but in some situations you need to write such information to the server like a database instead, cookies should not be used for critical information or any kind of sensitive information especially at a public faced site. However a cookie can be a great choice for many tasks in your front end development.

Some examples of the usefulness of a cookie

  • Change color schemes
  • Hide / Show elements at the page
  • Resizing fonts, scale up or down
  • Form, auto save inputs in fields, selected check box or radio button
  • Accordion / tabs, remember last state of collapsed/opened
  • Navigation, remember the last location
  • Welcome message, for example if you want to show a popup only once at specific date at the start page.

jQuery doesn’t support cookies natively but you can use a super small plugin called ‘jquery.cookie.js’  that contains all kind of basic functions and options you’ll need for your scripting. This plugin is also included in jQuery UI development-bundle.

Jquery.cookies gives a couple of options like:

  • Expires
    The lifetime for the cookie. You can use a number of days or a specific date. If omitted, the cookie is a session cookie
  • Path
    Where the cookie is valid. If you want it to be valid at every site in the site collection, just use a slash /, if you want it to be valid at let’s say only the news site set e.g /news/

Get going

Let’s start with a simple example just to get going, the following example will set the top row to a red or green background color depending of which link you click. Let’s say you clicked at green one and then reload the page, the green background color will remain. If you restart the browser, the top row will be white again. This script do not have any expired date, therefore, the cookie will expire automatically when you close the browser.

Let’s try this out:

Download jquery.cookies.js and create a reference to this file in your custom master, don’t forget to include an reference to latest jQuery API as well.

HTML
Put this somewhere in your custom master page

<!-- Session -->
<div class="Wrapper">
	<div class="Red">Red</div>
	<div class="Pipe">|</div>
	<div class="Green">Green</div>
</div>

jQuery
Put this in an external JS file referenced from your master page

$(document).ready(function() {

// Click red
$('.Red').click(function() {
$('.Wrapper').css("background-color","red");
$.cookie('Wrapper', 'red');
});

// Click green
$('.Green').click(function() {
$('.Wrapper').css("background-color","green");
$.cookie('Wrapper', 'green');
});

// Cookies
var Wrapper = $.cookie('Wrapper');
if (Wrapper == 'red') {
$('.Wrapper').css("background-color","red");
};
if (Wrapper == 'green') {
$('.Wrapper').css("background-color","green");
};

});

CSS
Put this in an external CSS file referenced from your master page

.Wrapper{
width:100%;height:16px;
background-color:#fff;color:#000;
}
.Red{
cursor:pointer;padding-left:5px;
float:left;
}
.Green{
cursor:pointer;float:left;
}
.Pipe{
float:left;padding:0px 5px 0px 5px
}

Maybe you want to set the cookie to a life span of 2 days, take a look at the jQuery script and the part where you set the name and the property:

$.cookie('Wrapper-', 'Green-');

Just add a path and a value; a number or a specific date, this will create the cookie

$.cookie('Wrapper-', 'Green-', {path: '/', expires: 2});

Take a look at the cookie in your disk, if you are using IE, you will find it through this path

C:\Users\...\AppData\Local\Microsoft\Windows\Temporary Internet Files

The file will contain the name of the cookie, the property and the path like this

Wrapper-Green-ecmtest67/108815182001923024639810215318430245996*

How to use cookies in a Data View web part

If we take this a step further and try to use cookies in a typical news roller DVWP. In this example, If you click at the icon next to the header for a news item that section will disappear, a kind of ‘I Have Read This’ function. At the bottom of the web part there’s a reset link that will delete the cookie.

The HTML part of the DVWP, it’s important to use @ID for the id, classes and href as the script shows

<div class="NewsRow {@ID}">
<div class="NewsContentContainer">			
<div class="NewsTitle">
<div class="NewsHider"><a href="{@ID}" id="{@ID}"><img alt="" src="/Style%20Library/Custom/Images/IhaveReadThis.png" width="22" height="22" /></a></div>
<div class="NewsTitleInner"><a href="/news/Pages/{@LinkFilename}"><xsl:value-of select="@Title" /></a></div>
<div class="GeneralClearBoth"></div>
</div>		
</div>
<div class="NewsAuthorCreatedWrap">
<span class="NewsAuthor">By <xsl:value-of select="@PublishingContact.title" />,</span> <span class="NewsCreated"><xsl:value-of select="@ArticleStartDate" /></span>
</div>
<div class="NewsContent">
<xsl:call-template name="FirstNWords">
<xsl:with-param name="TextData" select="$DescText"/>
<xsl:with-param name="WordCount" select="15"/>
<xsl:with-param name="MoreText" select="'...'"/>
</xsl:call-template>
</div>
</div>

The jQuery goes here

jQuery(function ($) {
var removedLinks = 'removedLinks'
,Options = {
expires: 7,
path: '/news'
},
c=$.cookie(removedLinks)||'#DebuggingCode'
$(c).remove();
$(".NewsHider a").click(function (e) {
e.preventDefault();
var LinkClass = '.'+ $(this).attr('id'),
removeLinksClasses=c.split(',')
$(LinkClass).remove()
removeLinksClasses.push(LinkClass)
c=removeLinksClasses.join(',') 
$.cookie(removedLinks, c, Options)
});
$('#NewsResetCookie').click(function(){
$.cookie(removedLinks,'',{expires:-1,path:'/news'})
})
});

If you prefer to use this in the ItemStyle.xsl and use it as a format for the Content Query web part, it works fine as well. If you want to take a look at a video of this, take a look here: http://youtu.be/kKEE_yktk8c

Hopes this give some ideas or inspiration for your cookie scripting adventures!
/ 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.

Branding the Quick launch in SharePoint 2010 – Part II — May 23, 2012

Branding the Quick launch in SharePoint 2010 – Part II

This post is the last one of two articles about some branding tips and tricks for the Quick launch in SharePoint 2010. In this article I’ll show you a simple way to add rounded corners with help of two background images at the top and bottom. Take a look at the first article here.

Let’s go – Example 1

Open your custom master page with SharePoint Designer and find the Sharepoint:SPNavigationManager control. Add the following DIV just above this control.

<div id="QLtopwrapper"></div>

When you complete this find the end tag of the </Sharepoint:SPNavigationManager> and add the following DIV just above this control.

<div id="QLbottomwrapper"></div>

Now you have everything in place in your custom master page as needed, so now it’s time to add some CSS. Copy the following CSS code and paste it into your external CSS file. As you can see I have used two background images. Make your own or download the Images I have used here. I have included my example master page in the download if you find it difficult to locate where you should place the top and bottom div.

/* |--------- Quicklaunch -----------| */
.ms-quickLaunch {padding-top:0px}
#s4-leftpanel-content{
background-color:transparent!important;
}
#s4-leftpanel-content {
border:0px!important;
background-color:transparent!important;
}
.s4-ql {
background-color:#fff;
margin-bottom:0px!important;
}
/* Inner nav element */
.menu-vertical {
padding:0px!important;
}
/* top rounded */
#QLtopwrapper {
background:url('/Style%20Library/Branding/Images/QLtop.png') repeat-x;
height:19px;
width:220px;
}
/* bottom rounded */
#QLbottomwrapper {
background:url('/Style%20Library/Branding/Images/QLbottom.png') repeat-x;
height:19px;
width:220px;
}
.menu-vertical > ul.root > li.static > .menu-item{
border-bottom:1px #929292 solid!important;
padding-left:0px;
color:#fff;
font-family:Arial;
font-size:11px;
font-weight:bold;
background-color:#8c8c8c!important;
background-color:#8C8C8C!important;
}
/* Selected */
.s4-ql a.selected {
background-color:transparent;
background-image:none;
border:1px transparent solid!important;
color:#fff!important;
}
/* no border in teamsites */
.s4-ql,.s4-specialNavLinkList{
border:0px!important;
}
.menu-vertical > ul.root > li.static {
padding:0px!important; margin:0px!important;
}
/* headers */
.menu-vertical > ul.root > li.static > a.menu-item {
padding:10px 4px 10px 5px;
border-bottom:1px #ccc solid;
}
/* headers selected for publishing sites */
.menu-vertical > ul.root > li.static > a.selected {
padding:10px 4px 10px 3px;!important;
padding-left:4px!important;
background-color:#777!important;
}
/* Subitem container */
.menu-vertical > ul.root > li.static > ul {
margin-bottom:0px;
padding-top:0px;
padding-bottom:0px;
}
/* SubItems wrap */
.menu-vertical > ul.root > li.static > ul.static > li.static > a  {
font-family:Arial, Helvetica, sans-serif;
font-size:11px;
padding:10px 4px 10px 8px;
color:#ccc!important;
}
/* SubItems  */
.menu-vertical > ul.root > li.static > ul.static > li.static > a > span > span {
color:#333;
text-decoration:none!important;
}
/* SubItems hover */
.menu-vertical > ul.root > li.static > ul.static > li.static a:hover {
text-decoration:none!important;
}
/* Selected SubItems  */
.menu-vertical > ul.root > li.static > ul.static > li.selected > a.selected {
background-color:#fff;
border:1px transparent solid!important;
padding-left:10px!important;
}
/* Selected SubItems  */
.menu-vertical > ul.root > li.static > ul.static > li.selected > a.selected > span > span {
color:#000;
}
.menu-vertical > ul.root > li.static > ul.static > li {
border-bottom:1px #8C8C8C solid!important;
}

Let’s go – Example 2

In this example I’ll use a jQuery script to get a simple and basic expand and collapse function in a specific scenario. Let’s say you have the setting “Display only the navigation items below the current site” for some site and have added headings and link manually. You can then use jQuery to toggle the headings. This behavior the jQuery script gives with the current navigation settings may not be suitable for all sites in the collection for you; this example is just build for this specific case and you can use it locally just on a single page if you prefer to.

Here’s the jQuery

$(".menu-vertical > ul.root > li.static > ul.static").css("display","none");
$(".menu-vertical > ul.root > li.static").css("background","url('/_layouts/images/plus.gif') no-repeat 3px 12px");
 
toggle();
function toggle() {
$(".menu-vertical > ul.root > li.static > a").toggle(
function () {
$("> ul", $(this).parent()).show("fast");
$($(this).parent()).css("background","url('/_layouts/images/minus.gif') no-repeat 3px 12px");
},
function () {
$("> ul", $(this).parent()).hide("fast");
$($(this).parent()).css("background","url('/_layouts/images/plus.gif') no-repeat 3px 12px");
});
}
$sel = $('.menu-vertical > ul.root > li.static > ul.static > li.selected');
if($sel.length) {
$sel.parent().css("display", "block");
$sel.parents().eq(1).css("background","url('/_layouts/images/minus.gif') no-repeat 3px 12px");	
}

Here’s the CSS

/* |--------- Quicklaunch -----------| */
.s4-ql A.selected {
background-color:transparent;
border:0px!important;
}
/* Inner nav element */
.menu-vertical {padding:10px; padding-left:0px}

/* Headers */
.menu-vertical > ul.root > li.static > a > span > span.menu-item-text {
border-bottom:1px #ccc solid;
padding-left:5px; color:#333;
padding-bottom:5px; padding-top:5px;
}
/* Sublinks */
.menu-vertical > ul.root ul > li > a {
padding-left:15px; color:#333; 
}
/* Sublinks hover */
.menu-vertical > ul.root ul > li > a:hover{
color:#009BA4; text-decoration: underline
}
/* Sublinks top and bottom */
.menu-vertical > ul.root ul {
margin-top:5px; margin-bottom:5px;
}
/* Sublinks selected */
.menu-vertical > ul.root > li.static > UL.static > li.selected > a.menu-item > span.additional-background{
margin-left:6px!important
}

Thanks & stay in tune!

/ Christian

Branding the Quick Launch in SharePoint 2010 – Part I — March 27, 2012

Branding the Quick Launch in SharePoint 2010 – Part I

This post describes how to customize the standard Quick Launch in SharePoint by using SharePoint Designer 2010.

Branding the Quick Launch with only CSS could be a bit tricky and it takes a little while to become a friend with the markup of this navigation and have it to look the way you want. This first article in a series of two will show you how to create a simple custom look and feel with only CSS code. If you need to create a more advanced design for the Quick launch than you can do with just CSS, the alternatives is to manipulate the DOM with jQuery or using plain HTML with CSS and background images. Besides of this, CSS 3 comes with some exiting features 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. I hope this post gives you some ideas and inspirations for branding the quick launch in the way you want.

Let’s go

Open SPD, create a custom master page and include a reference to an external CSS file. Paste the following CSS code in your custom CSS file. Save and publish the files and apply the master page to a site or your site collection. Use the browser and go to a site where you can see a Quick Launch to verify the changes. This first example uses a list style background image for the sub items. You can download the arrow icon here.

CSS

Add this CSS in your custom CSS file, don’t forget to change the path to the arrow icon to the folder where you put the image:

/* |--------- Quicklaunch -----------| */
.s4-ql ul.root ul {
margin-bottom:5px;
}
/* Outher nav element */
#s4-leftpanel-content{
background-color:#fff!important;
border:1px #d8d6d7 solid!important;
border:0px!important
}
/* Inner nav element */
.menu-vertical {
padding-right:10px!important;
padding-left:10px!important;
}
/* Inner Inner nav element */
.menu-vertical > ul.root {
padding-top:3px;
}
/* mainlinks */
.menu-vertical > ul.root > li.static > .menu-item{
border-bottom:1px #555 solid!important;
padding:1px 1px 1px 0px!important;
color:#333!important;
}
/* Sublinks */
.menu-vertical > ul.root > li.static > ul.static  {
margin-top:5px; margin-bottom:5px;
}
.menu-vertical > ul.root > li.static > ul.static > li.static > a > span > span {
margin-top:2px
}
/* Selected */
.menu-vertical > ul.root > li.selected > a {
background-color:transparent!important;
border:0px; margin:0px; padding:0px;
}
.menu-vertical > ul.root > li.static > ul.static > li > a.selected {
background-image:none!important;
background-color:transparent;
color:green!important;
border:0px; margin-top:1px;
}
/* no border for the QL when no links */
.s4-specialNavLinkList {
border:0px
}
/* Liststyle square */
.s4-ql ul.root ul > li  { 
padding-top:0px; 
background-image:url('/Style Library/WordPress/Images/Arrow-Right.png');
background-repeat:no-repeat;
background-position:0.0em;
}
/* Liststyle square links */
.s4-ql ul.root ul > li > a { 
display: inline-block!important; 
padding-top:0px;
padding-bottom:0px!important; 
padding-left:0px!important;
margin-left:16px;
vertical-align:top!important; 
}

Another example

If you want to display more levels in the Quick Launch you can set the display level to three, MaximumDynamicDisplayLevels=”3″ for the SharePoint Asp menu in the master page. Look for the menu control with the ID V4QuickLaunchMenu. In this example I have used list-style squares instead of the arrows.

Add this CSS in your custom CSS file:

/* |--------- Quicklaunch -----------| */
.s4-ql ul.root ul {
margin-bottom:5px;
}
/* Outher nav element */
#s4-leftpanel-content{
background-color:#fff!important;
border:1px #d8d6d7 solid!important;
border:0px!important
}
/* Inner nav element */
.menu-vertical {
padding-right:10px!important;
padding-left:10px!important;
}
/* Inner Inner nav element */
.menu-vertical > ul.root {
padding-top:3px;
}
/* mainlinks */
.menu-vertical > ul.root > li.static > .menu-item{
border-bottom:1px #555 solid!important;
padding-left:0px!important;
padding:1px!important;
color:#333!important;
}
/* Sublinks margins */
.menu-vertical > ul.root > li.static > ul.static  {
margin-top:5px;
margin-bottom:5px;
}
/* Selected */
.menu-vertical > ul.root > li.selected > a {
background-color:transparent!important;
border:0px; margin:0px; padding:0px
}
.menu-vertical > ul.root > li.static > ul.static > li > a.selected {
background-image:none!important;
background-color:transparent;
color:green!important;
border:0px; margin-top:1px;
}
/* no border for the QL when no links */
.s4-specialNavLinkList {
border:0px
}
/* Liststyle square */
.s4-ql ul.root ul > li  { 
list-style:square inside !important; 
list-style-position:outside !important; 
margin-left: 23px !important; 
padding-top:0px; 
}
/* Liststyle square links */
.s4-ql ul.root ul > li > a { 
display: inline-block!important; 
padding-top:0px; 
padding-bottom:5px!important; 
padding-left:0px!important; 
vertical-align:top!important; 
}
/* If 3 lvl in QL */
/* Wrapper for all Items in lvl 3 */
.menu-vertical > ul.root > li.static > ul.static > li.static > ul.dynamic {
position:relative;
left:-8px!important; 
top:1px!important;
padding-left:0px
}
/* Wrapp each Item in lvl 3 */
.menu-vertical > ul.root > li.static > ul.static > li.static > ul.dynamic > li.dynamic {}
.menu-vertical > ul.root > li.static > ul.static > li.static > ul.dynamic a:hover {}
.menu-vertical > ul.root > li.static > ul.static > li.dynamic-children > a.dynamic-children > span.additional-background {
background-image:none
}
/* Items in level 3*/
.menu-vertical > ul.root > li > ul > li > ul > li > a.selected > span > span  {
padding-left:5px!important
}
/* Item lvl 3 - get all subItems from the last available DOM defined selected Item */
.menu-vertical > ul.root > li > ul > li.selected > ul > li > a > span > span {}

Read more about customizing the Quick Launch at MSDN library How to: Customize the Display of Quick Launch

In the next blog post I’ll show you some more examples how to customize the quick launch with stuff like rounded corner & borders and how to expand / collapse the Quick Launch with help of jQuery. Stay in tune!

/ Christian

Create a Microblog for SharePoint 2010 — February 11, 2012

Create a Microblog for SharePoint 2010

This post is about how to create a Microblog with SharePoint Designer 2010 and the use of DVWPs, CSS and jQuery. A Microblog can be used for quick communication with team members in short sentences at the Intranet. This example works just like a SharePoint blog site, posts and comments are stored in separate lists that are linked by a lookup and team members can add posts and anyone can reply to posts. This Microblog is a basic no code solution and if you are looking for more advanced social features like hash tagging, direct messages, document uploading or integration of my site you should check out tools like NewsGator or Yammer among more. If you are looking for a basic comment function, maybe the OTB web part Note board could be an option. But let’s look into how you can use the DWVP for a Microblog.

Let’s try it out

  • Open the browser and create two custom lists in the root site of your Site Collection
    • Name it ListPosts
    • Name it ListComments
  • ListPosts
    • Create a column:
    • Name: Content – Multi lines of text with three lines for editing and plain text type.
    • Go to list settings, click the Created By column and change the presentation for this field to Name (with picture).
    • Add a new Item in the list with a title and a comment.
  • ListComments
    • Create two columns:
    • Name: PostsID – type Lookup. Get information from ListPosts in the ID column. Do not allow multiple values.
    • Name:  Comments – Multi lines of text with three lines for editing and plain text type.
    • Go to list settings, click the Created By column and change the presentation for this field to Name (with picture).
    • If you don’t use English language, rename the the (Title) column to Title, another way is just to set this column as optional if you prefer.
    • Add a new Item in the list with a title and a comment. Type a title, select PostID according to the ID from the ListPosts item you added and add a comment.

Create a Linked Data Source for the posts and comments lists

  • Open the root site with SPD and click at site objects in the left navigation at click Data Sources. Click at Linked Data Source in the ribbon. Give it the name MicroBlog in the General tab and click at configure Linked Source in the Source tab.
  • Select ListPosts and ListComments and add them to the right pane. If you can’t see the list you have to update SPD. Click at the next button and select Join and click at Finish and OK.
  • Open the root site with SPD and create a new folder named SPD-WebParts
  • Create a new ASPX page called MicroBlog and save it in the folder you created, open the page with SPD. IF you download my pages and will copy and paste you don’t need to do more now, but if you want to set this up by your self you can attach the page to your custom master page. Check it out, click at the Style tab in the ribbon, the button Attach and attach it as a custom master page. In the design view, click at the right arrow for the PlaceHolderMain place holder and click at create custom content.
  • Create a new ASPX page called MicroBlogForm and save it in the same folder as Microblog.aspx. Repeat the steps as you just did for the MicroBlog.aspx.

Create two ASPX pages

In the next step it’s time to create two DVWPs for MicroBlog.aspx, the first is for inserting posts and the second is for displaying current posts and their comments. If you want to build this by yourself you can just add a Display Item Form DVWP and use the Linked Sources and then insert field from the Comments as a Joined sub view. You will also have to create a New Item Form DVWP for the second page meant for inserting comments.

If I would describe all the steps from now including styling and jQuery this blog would be too long and for this reason I have prepared this so it’s just to download the pages and do some copy and paste. If you export or upload the DVWPs as web parts the CSS and the jQuery will not follow the web part. so cut the CSS from the MicroBlogForm page and paste this into an external CSS file. The same goes for the jQuery stuff in both pages, cut the scripts and paste them into the head section of your custom master or into an external JS file.

Read more about Linked data sources at the Microsoft Office SPD pages.

Insert the Dataviews into the ASPX pages

MicroBlog.txt

  • Open this page and copy the content into MicroBlog.aspx and save the page

MicroBlogForm.txt

  • Open this page and copy the content into MicroBlogForm.aspx and save the page

CSS

Copy this CSS into your custom CSS file

/* --- MicroBlog --- */
.PostBodyWrapper {width:100%;}
.PostWrapper {margin-left:5px}
.PostSeparator {border-bottom:1px #f1f1f1 solid; border-top:1px #fff solid; margin:5px 5px 5px 5px}
.PostImg {float:left; width:50px; height:50px; padding-right:10px}
.PostContentWrapper {background-color: #fff; height:50px;}
.PostEditor {font-weight:bold; color: #0072bc}
.PostContent {}
.PostLink {}
.PostComment {}
.PostCreatePost {padding:10px}
.FormFieldMicroBlogWrapper {margin-left:5px; width:100%; }
.FormFieldMicroBlog > span > textarea {
background-color: transparent; width:95%;
border:1px solid #ccc;        
overflow:hidden; overflow-y: hidden; overflow-x: hidden;   
font-size:14px; color:#999;
font-family:Arial, Helvetica, sans-serif;
padding:10px 20px 0px 10px;
margin-right:20px
}
.PostBtn {padding-right:3px; float:left}
.PostBtn Input {
width: auto;
padding: 5px 10px 5px 10px;
background: #617798;
border: 0;
font-size:13px;
color: #fff;
cursor: pointer!important;
float:right
}
.CommentWrapper {margin-left:60px; margin-right:5px; background-color: #f7f7f7; padding:10px; border-bottom:1px #fff solid}
.CommentImg {width:50px; float:left;}
.CommentContentWrapper {}
.CommentEditor {font-weight:bold; float:left}
.CommentEnd {margin-left:60px; margin-right:5px; border-top:1px #ccc solid; border-bottom:1px #fff solid; margin-bottom:20px}
.CommentContent {}
.CommentLink {}
.CommentNoComment {border-bottom:1px #fff solid; border-top:1px #fff solid; margin:0px 0px 15px 0px}
/* --- End MicroBlog --- */

Jquery

Copy this jQuery into your custom master or into a referenced JS file

$(document).ready(function() {
$(function() {
// Remove autofocus
$("textarea[title='Content']").blur();
// Set defaulttext
var defaultText = 'What are you working on?';
$("textarea[title='Content']")  
// Handle blur effect  
.val(defaultText)
.focus(function() {
if ( this.value == defaultText ) this.value = ''
})
.blur(function() {
if ( !$.trim( this.value ) ) this.value = defaultText
});});
});

Image Paths

If you not have activated the user profiles and my site, you have to change the image path in the MicroBlog file. You can create an image library in the root site and store the user images there if you want. Just name the images same as the Users ID. The path can looks like:

<img src=”/RootImages/{@Author.id}.jpg” alt=”” width=”50″ height=”50″ />

Ready to test

Finally it’s time to try this out, open your browser and to to the MicroBlog page

Behind the scenes

Some notes if you needs to change something

  • You have to reference the latest jQuery file in your custom master page
  • Save the two web parts into the web part gallery, or export them as files and you can use them at any page in the site collection, not only at the root site.
  • I have set a RowLimit variable to 5 In MicroBlog.aspx, change this as you prefer.
  • I changed the variable that Joins the list to get rid of the unwanted characters
    <xsl:variable name=”Rows” select=”../../../ListComments/Rows/Row[substring-before(@PostsID., ‘;#’) = normalize-space($dvt_ParentRow/@ID)]”/>
  • The link ‘Reply’ sends the current posts ID as a query string over to the next page (the dialogue). I have used a bit jQuery go get this ID from the URL in order to prepopulate a hidden drop down (the lookup column), and as you may know if there are 20 or more items in a list and you use lookup to this list, the select drop down will be converted to an input drop down and this needs to be solved as well.
  • In the dialog I used a SharePoint:SaveButton as I think is an easy way to close a dialog when click the save button.

The jQuery used in the MicroBlogForm that sets the Post ID into the hidden dropdown.

$(document).ready(function() {
var loc = window.location.href.substr(window.location.href.lastIndexOf("/")).replace('/MicroBlogForm.aspx?CID=', '').replace('&IsDlg=1', ''); 
var HiddenInput = $("input[title='PostsID']").attr("optHid");$("select[title='PostsID']").val(loc);	
$("input[title='PostsID']").val(loc);	
$("input[id='" + HiddenInput +"']").attr("value",(loc))
$('input[title="Title"]').val(loc); 
$(".FormFieldShow > span > textarea").focus(); 
});

More to do

If someone’s profile picture should be broken or missing, you can use jQuery to replace a broken image with an shadow image:

$(window).bind('load', function() { 
$('img.resizeme').each(function() { 
    if((typeof this.naturalWidth != "undefined" && 
        this.naturalWidth == 0 )  
        || this.readyState == 'uninitialized' ) { 
        $(this).attr('src', '/_layouts/images/O14_person_placeHolder_32.png'); 
    } 
}); 
})

Enjoy, and drop a comment if you have something to ask
/ Christian