Thursday, January 26, 2006

Extreme SharePoint Design: Customizing SharePoint Administration Pages

Administration pages in SharePoint are often the Achilles heel of a customized portal design – they exist outside of the site definition framework, they don’t inherit templates, and they implement a confusing array of shared code structures. This can create usability issues as users switch from a cohesive design on default and list pages to the default GUI and navigation when trying to create a new list or add an alert.

Depending on your design, customizing administration pages can quickly become a nightmare – if just modifying the header is not enough then you’re in for a bumpy road ahead. Here are a few tips that can help you get from stock to custom without the need for a morphine I.V. drip:

Primary Page Structures

There are 215 .ASPX files in the /layouts/1033 directory. Seventy-eight percent of these fall into one of two primary code structures. For simplicity, we’ll call them the ‘SPS’ style and ‘WSS’ style. The SPS style relies upon a server-control structure to render page content; the WSS style uses more traditional HTML code to display content.

The following code renders the page header in the SPS style:

This is how the same header is retrieved in the WSS style:

The most important difference between the two files is the WSS style’s utilization of the AlternateHeader property. The code first checks to see if an alternate header exists – either PORTALHEADER.ASPX or ALTERNATEHEADER.ASPX – and, if so, retrieves the code from the file and renders it; if not, it renders the code between the if…else blocks. This is a useful mechanism because the alternate header files function the same way as a user control – a central file that can be modified to match the new portal design scheme and is accessed from many pages – but it’s only applicable to the WSS style. How do we apply this same concept to the SPS style?

User Controls

Directly modifying the SPS style pages to replace the header is pretty straightforward – just replace the contents between the SPSWC:PageHeader tags (if you aren’t going to use the SPSWC:CategoryNavigationWebPart control in your code, be sure to leave it in place and comment it out). The problem is that there are 67 of these files so maintaining the customized code can become an issue. The solution is to implement a user control to replace the default code and duplicate the alternate header functionality. But there is a catch (naturally).

Pages in the /layouts/1033 directory can utilize external code files but only if they reside in the same directory. So, unlike site defintion files, for which user controls are normally stored in the virtual server /bin directory, any controls created for administration pages must be stored in /layouts/1033; otherwise, the process is the same. Create the replacement code, save it in an .ASCX file in the /layouts/1033 directory, and reference it from each administration page.

First, remember that when creating a user control you need the correct page registrations for any code contained within the file. The standard registrations are:

<%@ Control Language="c#" AutoEventWireup="false" TargetSchema="http://schemas.microsoft.com/intellisense/ie5"%>;
<%@ Register Tagprefix="WebPartPages" Namespace="Microsoft.SharePoint.WebPartPages" Assembly="Microsoft.SharePoint, Version=11.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c"%>
<%@ Register Tagprefix="SPSWC" Namespace="Microsoft.SharePoint.Portal.WebControls" Assembly="Microsoft.SharePoint.Portal, Version=11.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c"%>
<%@ Register Tagprefix="SharePoint" Namespace="Microsoft.SharePoint.WebControls" Assembly="Microsoft.SharePoint, Version=11.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c"%>
<%@ Register Tagprefix="Utilities" Namespace="Microsoft.SharePoint.Utilities" Assembly="Microsoft.SharePoint, Version=11.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c"%>

You’ll also need to register the new user control at the top of each administration page, like this:

<%@ Register Tagprefix="CUSTOMUC" Tagname="spsPortalHeader" src="spsPortalHeader.ascx"%>

You can then call the code from within the page by placing the user control reference between the SPSWC:TopPageSection tags. For example:

<CUSTOMUC:spsPortalHeader id="spsPortalHeader" runat="server"></CUSTOMUC:spsPortalHeader>

Of course, you still have to modify all 67 SPS style pages but by implementing user controls you only have to do this once; after that, you make changes only to the .ASCX file and they will be propagated automatically.

Beyond Headers

Sadly, replacing headers is the easiest part of administration file customization. Beyond that you enter into the realm of painful line-by-line replacement. WSS style pages are a bit easier as you have direct access to the page body code, which can be edited easily enough (user controls can also save you some headaches here), but watch out – the structures change slightly from page to page and there are often hard-coded elements (such as page titles) so be careful how much editing you do. The same can’t be said for SPS style pages – they use nothing but server controls to render code.

The good news on both fronts is that creative manipulation of style sheets can overcome most design challenges, as long as you’re willing to live with the boxy and boring standard white content area. The primary styles in play here are ms-nav, ms-navframe, ms-titlearea, ms-titleareaframe, ms-titlearealine, ms-verticaldots, ms-colspace, ms-pageidi, ms-pageidpt, and ms-pageidta. You’ll also have to deal with the stock images at the top of the left column by moving them around or making them disappear altogether. Assuming you’ve already modified the styles for the navigation frame on the left and the associated menus, you should be well on your way to improving the bland look of those finicky administration pages.

Happy SharePointing!

UPDATE: Need to get rid of that pesky image at the top of the left column in the SPS style? Try Mike Rundle's text-hiding method. Add this to your style sheet:

.ms-pageidi
{ text-align: -100px }

Image be gone! (Note: it's still there, the text-align setting just moves it off the page where it can't be seen)

Tuesday, January 24, 2006

SharePoint UK User Group First Meeting

Nick Swan has done a tremendous job putting together the SharePoint UK User Group.  They’ve got a great site with some really good info for UK SharePointers.  Their first meeting is being held Monday, February 13th.  I know how much work goes into organizing these events so hats off to Nick and his team.  If you live anywhere close to Thames Valley Park in Reading you should make every effort to attend (there are also some great pubs nearby so it’s definitely worth the trip).   

Go here for all the information. 

I do a fair amount of business in the UK and they really have a thriving SharePoint community.  It’s great to see them getting support from Microsoft.  Unfortunately I’m on a project Stateside all through February or I would be there to support the group.  Have a pint of Abbott Ale for me, mates! 

Wednesday, January 18, 2006

SharePoint Communities

Lately, there’s been a great deal of debate about forming communities to centralize/aggregate/organize SharePoint-related content.  I think every one of us who pontificates on SharePoint has lamented the lack of a distinct community structure at some point.  There is no doubt that it’s frustrating, especially for new users, to find SharePoint content, tips, tricks, advice, code, best practices, and the like.  There are blogs, aggregators, community sites, MSD2D, newsgroups – the list goes on and on.  Now that’s the definition of confusion.

No one can really agree on how best to approach this problem – although we’re all aware that there is, indeed, a problem – but there seem to be three main approaches:

1. Centralization

Proponents of this approach believe that the only way to tame the beast is to bring all of the various resources together under one roof (which usually means THEIR roof) to provide a one-stop-shopping approach.  While this initially sounds like an attractive proposition, there are all kinds of issues, like: Who controls the platform?  Who determines format? Who maintains the directory?  Who has final say on contributions and content? Is somebody profiting disproportionately from it?  How are contributors engaged?  Who gets the AdSense revenue?

One very important shortcoming of a centralized resource is that a structured framework by its very nature is anathema to creativity.  Most community contributors see their sites/blogs as labors of love and means of expression – they don’t want to use somebody else’s template or format or rules.  Centralization is their kryptonite – they work under too many restrictions from day to day and free expression of their ideas is a constructive outlet.  The overall community may not need yet another WSS site with a fancy template and a bit of original content but the person who built it needs it for their own personal satisfaction and edification.  This is a powerful factor that cannot be overlooked (and too often is).

And let’s not be so blind as to think that there is not a profit motive behind many of these efforts; often times somebody, somewhere, wants to get paid (which is neither good nor bad, it’s just reality).  There’s a natural level of distrust between the community and the people who run commercial enterprises; they assume, whether right or wrong, that the business owner wants their content for the sole purpose of enriching themselves.  In truth, that’s probably a rare occurrence (I can’t think of one example in the SharePoint community where this is absolutely the case), but the perception still exists.  This is the true Achilles heel of centralization.

Then, of course, there is Microsoft’s centralization effort, which you would think lends itself most to the profit motive argument but in reality is probably the least likely to support that hypothesis (Microsoft is going to sell lots of CAL’s regardless of what all of us post on the web).  There’s lots of distrust here too but for a different reason – people are worried that Microsoft will police their contributions, stifling dissent and revoking it’s favor (like MVP status) for those that don’t toe the line.  I don’t know if this will really happen or not but I will admit that it concerns me – how long do you think my Extreme SharePoint Design series of posts would last on an MS sponsored site?  They’d never make it past the editors, I would imagine, because they show users how to solve problems or overcome inbuilt limitations that don’t necessarily jive with what MS defines as a ‘supported’ solution.   

Having said all that, what are the advantages of centralization?  Ease of use, for one, especially for new users.  Efficiency as well, in that we would all spend less time searching for what we need to know.  I suppose a certain level of consistency would also be achieved along with elimination of duplication if everyone is aware of what other contributors are saying.  There’s probably a bit of esprit de corps that would go along with being on the same team and enthusiasm, as we all know, is infectious.  And let’s not forget that together we could probably achieve more in one form or fashion than we could each working on our own.

So are the benefits enough to outweigh the disadvantages?  I suppose the community at large will decide, or they may choose…

2. Decentralization

This model leaves things just as they are.  Lots of different content islands floating around the SharePoint ocean with no direct links between them.  Users leverage existing tools like Google, MSN, Yahoo!, Technorati, Feedster, and RSS feed readers/aggregators to find what they’re looking for.  Convenient?  No.  Efficient?  Not even close.  Effective?  Hardly.  But it is easy, as no one has to build or maintain a centralized resource, and it doesn’t require users to do anything different than what they already do when looking for other types of information. 

This model is already in place and, if it were working well, I imagine that fewer people would be decrying the current state of affairs, so something is rotten in Denmark (my express apologies to our Danish friends for that turn of phrase).  I know how confusing it is for new SharePointers – I hear from my clients all the time about how hard it is to find good information.  Frankly, there’s just too much out there for them to catalog and synthesize.  It’s second nature to us because we live and breathe this stuff every day but they have real jobs with other responsibilities.  And I know lots of people want access to more resources because the most popular feature on my web site is my blogroll (I wish it were the description of my service offerings or my contact page but sadly it is not to be). 

It’s also very hard to discover new content in a decentralized model.  When all the information is pulled instead of pushed you have to know exactly what you’re looking for.  Free association is no strong point here – if you’re looking for needles, that’s what you’re going to get, even if a match stick might work better.  It’s no secret that you always find what you were looking for yesterday when you’re looking for something else today.  By way of example, Heather has one of the best resources on the web for SharePoint customization but people still post questions to the newsgroups that she has long since answered in-depth.  I wish more people would use SharePoint BlogSearch but they don’t – it’s mostly a handy tool for me to find postings from other bloggers without wading through Technorati’s endless parade of irrelevant results.  And just a few months ago I had a user point me to one of Bil Simser’s posts on automating list metadata from Word documents that I was unaware of – and I read Bil’s blog religiously!  Talk about an embarrassing moment; if I don’t know these things off the top of my head, how on earth is Joe SharePoint Administrator supposed to cope?  There’s just too much out there for anyone to get a good handle on.

Which leads us to…

3. Affiliation

This is a middle-of-the-road approach that places more importance on the connections between contributors than it does on command and control.  A Federalist solution, this model encompasses as many content islands as everyone can build so long as there are good links between the islands, perhaps with a DNS-root-server type of directory listing hosted somewhere.  This is in line with the organic growth model of most online communities and eschews any sort of governance other than mutual accountability. 

As with any group of city-states, the overall economy of the region is only as good as the trade routes between destinations.  In other words, if we can’t all agree on some uniform method of linking to each other and cross-publishing then the whole garment will unravel.  We know the ‘web ring’ concept doesn’t really work, so we’ll have to come up with a better method of maintaining the roadways between our islands.  And there still has to be a unified directory somewhere, which opens up the same control issues as complete centralization. 

This method does seem, at least on the face of it, to blend the best of both the centralized and decentralized approaches.  Yes, we all have to agree on some way to keep traffic flowing between us, but it would sure make the task of finding information easier.  And contributors would be free to exercise their creative talents.  The directory is a problem, if for no other reason than someone is going to have the task of maintaining it, and it will have to contain real or near real-time information.  No easy task, to be sure.

 

So what’s the final solution?  I don’t know any more than you do.  Personally, I think the Affiliation model works the best but I could be wrong – I know several of my clients would much prefer Centralization because it makes their work lives easier but many community members are staunch adherents to the Decentralization metaphor.  The two constituencies seem to be at opposite ends of the spectrum.  Judging by the community reaction to any proposition for centralization, I doubt we will see this happen any time soon so it may become the de facto loser, with decentralization winning by default since it requires no additional effort on our part (I sure hope that’s not the reason but we can’t rule out general sloth as a factor).  One thing’s for sure – spirited debate on the subject isn’t about to die any time soon!            

Tuesday, January 17, 2006

SharePoint BlogSearch Update

I have updated SharePoint BlogSearch with a bunch of new blogs (see a complete list of included blogs here). I've also modified some of the search parameters to return more relevant results and better default groupings. Incremental updates are now being done weekly to conserve bandwidth; hopefully, this won't cause adversely affect any search results. Should you notice something missing that needs to be there just email me and I'll check it out.

I've also added a BlogSearch form to the main page; just go to The eGroup Web Site and you'll see it on the right side of the page. If you'd like to use this form on your web or blog site, copy and paste the following code into your HTML (style references are included so you can add them to your default CSS and change them accordingly):

<form method="get" action="http://www.theegroup.net/search.aspx" target="_top">
<table width="250" border="0" cellspacing="0" cellpadding="0">
<tr>
<td align="left" valign="bottom" style="padding-right: 3px"><img src="http://www.theegroup.net/_layouts/images/SPSSearch2.gif"></td>
<td align="left" valign="bottom" style="font-weight: bold; font-family: verdana, arial, helvetica, sans-serif; color: #1B6E89; padding-bottom: 3px; font-size: 8pt;">SharePoint BlogSearch</td>
<td></td>
</tr>
<tr>
<td></td>
<td align="left" valign="bottom" style="font-family: verdana, arial, helvetica, sans-serif; font-size: 8pt"><input type="text" name="k" size="35"/><input type="hidden" name="s" value="SharePoint%20Blogs"/></td>
<td align="left" valign="middle" style="padding-left: 3px"><input type="image" name="Submit" src="http://www.theegroup.net/_layouts/images/icongo02.gif"/></td>
</tr>
</table>
</form>

As always, let me know if a blog is missing that should be on the list or if you would like your blog excluded from the index.

Happy blogsearching!

Thursday, January 12, 2006

SharePoint Forge Opens Its Doors

Many of us have complained in the past that there is no central repository for SharePoint knowledge, code, web parts, techniques, etc. Well, those days are over. Bil Simser's SharePointForge is now open for business.

Go check it out and let Bil know how much you appreciate his hard work.

Wednesday, January 11, 2006

An Open Letter to SharePoint Recruiters

I get a lot of emails from recruiters looking for SharePoint resources. I welcome every message and try my best to connect the people I know with each opportunity that comes my way. One thing that I see over and over again is a job requirement that demands top-notch coding skills alongside advanced design/customization/deployment/project management knowledge. This is like asking the guy at GM who designed your SUV to also be the mechanic - they are two completely separate disciplines and anyone who claims to be good at both is going to be horrible at each one.

When was the last time you saw an architect framing a house and doing the brickwork? Or a graphic designer building a server farm? Or a nurse doing brain surgery?

Software architects and software developers have completely different skill sets. Yes, some skills overlap to a small degree, and knowledge of one discipline can make you better at the other, but to be really good at something you have to focus on that skill to the detriment of all others. I don’t write code not because I can’t but because there are people out there who can program circles around me with their eyes closed - but ask those same superstar developers to manage an end-to-end portal implementation or do all the design and customization work to take a project from mock-up to production and you’ll get that deer-in-the-headlights look. They’ll tell you straight up that’s not what they do, that’s what architects and designers do. And if they don’t then they are a) lying and b) bad developers. Don’t hire them. Period.

So please, to every recruiter out there, stop trying to shoe-horn two bodies into a single position - it won’t work and your client will definitely not be happy with the result. If you get a requisition with this type of ridiculous stipulation it’s your job to tell the hiring manager that he/she needs two experts, not one, and you’ll be happy to go find them both. Let people do what they do best - good personnel placement is about fitting round pegs into round holes not drilling out bigger holes to make room for triangles, squares and octagons.

</rant>

SharePoint User Interface Customization

Heather has a great new article on customizing the SharePoint user interface. Like her, I wish I could give you a step-by-step guide on how to do it but there's just no simple solution (here are a few tips to get you started ). In Heather's words:

Customizing SharePoint is like riding a bike, it is very hard to tell someone how to do it, and that person really just has to try, fall down, try again, and they will figure it out.

I couldn't agree more.

Tuesday, January 10, 2006

Extreme SharePoint Design: Custom MySite Titles, Part 2

In a previous post I demonstrated how to create custom titles on MySite pages that display the site owner's name and link back to the public view if the viewer is just a reader and the private view if the viewer is the site owner. The example used the Title property of the SPControl.GetContextWeb(Context) method to retrieve the site owner's name from AD. This works fine if the correct fields in AD have the right information in the right format (i.e First Name, Middle Initial, Last Name) but not so well if they don't. In many cases, the system returns the user name in the Windows default format of [Domain]\[Username].

Fortunately, SharePoint user profiles contain the user's full name, which is rendered in the <SPSWC:PersonalSpaceMainHeading> control; unfortunately, this information is not directly accessible via the object model and, like the Title property, the name is displayed in the 'Last Name, First Name' format. To further complicate matters, the PersonalSpaceMainHeading control insists on displaying an icon that indicates whether or not the user is logged into the system, even if the RenderPawn option is set to 'False'.

To circumvent these issues and insure that the user name is rendered as 'First Name, Last Name' in all instances, we'll first hide the <SPSWC:PersonalSpaceMainHeading> control on the page, then access it's innerText property to get the user name. Then we'll parse the user name into the correct format and apply logic to determine whether the user is a reader or site owner and then write out the proper link.

First, create a blank user control (server and client-side code are blocked from execution in a standard portal page) with the following registrations:

<%@ Control Language="c#" AutoEventWireup="false" TargetSchema="http://schemas.microsoft.com/intellisense/ie5" %>
<%@ Register Tagprefix="SharePoint" Namespace="Microsoft.SharePoint.WebControls" Assembly="Microsoft.SharePoint, Version=11.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>
<%@ Register Tagprefix="SPSWC" Namespace="Microsoft.SharePoint.Portal.WebControls" Assembly="Microsoft.SharePoint.Portal, Version=11.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>

Store the control in the /bin directory of your SharePoint virtual server. For this example, the control is named 'spsTitle_MySite.ascx'.

Next, create the container code for the display of the user name. For this application, we are simply enclosing the user name in a table with two cells: one that reads 'Personal Site' and one that displays the user name. Place the <SPSWC:PersonalSpaceMainHeading> control into a hidden DIV so it can be accessed later in the code:

<table align="left" cellpadding="0" cellspacing="0" border="0">
<tr>
<td width="5"></td>
<td valign="middle" class="Mysite">Personal Site</td>
<td valign="middle" class="Mysite_Title"><div id="PersonalSpaceMainHeading" style="display:none"><SPSWC:PersonalSpaceMainHeading RenderPawn="false" runat="server" /></div></td>
</tr>
</table>

Next, combine a server-side 'If...Then' statement with client-side Javascript which extracts the innerText of the PersonalSpaceMainHeading control and renders the user name and correct link:

<% if (SPControl.GetContextWeb(Context).CurrentUser.LoginName == SPControl.GetContextWeb(Context).Author.LoginName) { %>
<script>
var strFullName = document.getElementById("PersonalSpaceMainHeading").innerText;
var intLength = strFullName.length;
var intLocation = strFullName.indexOf(", ");
if (intLocation == -1)
{
strTitle = strFullName;
}
else
{
strTitle = strFullName.substring(intLocation + 1) + " " + strFullName.substring(0, intLocation);
}
document.write("<a href='/mysite/default.aspx'>" + strTitle + "</a>");
</script>
<% } else { %>
<script>
var strFullName = document.getElementById("PersonalSpaceMainHeading").innerText;
var strUrl = window.location.href;
var intLength = strFullName.length;
var intLocation = strFullName.indexOf(", ");
if (intLocation == -1)
{
strTitle = strFullName;
}
else
{
strTitle = strFullName.substring(intLocation + 1) + " " + strFullName.substring(0, intLocation);

}
document.write("<a href='" + strUrl + "'>" + strTitle + "</a>");
</script>
<% } %>

The first part of the 'If...' statement checks to see if the current user name matches the login name of the site author. Since personal sites are created by the user, the Author will always be the site owner. If the name matches, the subsequent javascript extracts the user name, parses out the comma and reverses the last name and first name (the full name is displayed in the 'Last Name, First Name' format by default). It then creates a hyperlink to the default (private view) of the personal site.

If the current user is not the author, the second javascript performs the same string manipulation then writes out the hyperlink using the public view URL (i.e. "/mysite/public.aspx?accountname=[UserID]"). This method will also work on shared and private libraries, personal pages, and lists, sending the user to the proper home page depending upon their role.

Now we'll need to call the user control from DEFAULT.ASPX and PUBLIC.ASPX. First, add a registration for your new control to the top of each page:

<%@ Register Tagprefix="UC" Tagname="spsTitle_MySite" src="/bin/spsTitle_MySite.ascx" %>

Next, call the control from the body of the page:

<td align="left" valign="middle">
<UC:spsTitle_MySite id="spsTitle_MySite" runat="server"></UC:spsTitle_MySite>
</td>

The final output looks something like this (you can modify the styles to render the link however you wish):


Monday, January 09, 2006

New SharePoint Discussion Forum Web Part

Bil Simser has a new post describing a Discussion Forum web part he's working on. I can't tell you how many times I get asked about a replacement for the built-in discussion functionality. This is great news. I can't wait to get my 'grubby little hands' on it when it's finished.

Way to go, Bil!

Friday, January 06, 2006

Customizing the Built-In SharePoint Menus

In previous posts (here and here) I’ve shown you how to build your own custom menus to relocate the standad Actions and Views menus. Great if you’ve got the time and the need to do so but what if all you want is a quick menu solution that looks and works just like the Modify Shared Page menu? Well, Gert van Bael has the answer. In this post he shows you how to duplicate the existing menu code to create a custom drop-down that supports nested menus.

Great tip, Gert!

Update: Dustin has a previous post on the same topic here.