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.

Don't Fire the Messenger

Recently I had a conversation with a prospective client in which it became apparent that a sales engineer had given them bad advice. It fell to me to explain the shortcomings of the SE’s recommendations, as gently as possible, to an IT manager who had only a very short time frame to impelement a large, customized SharePoint solution. He didn’t take it very well, so needless to say, I don’t think I’ll be getting the engagement.

I see this happen quite frequently and it always ends up with the consultant being the bad guy. I hate to break this to the world at large but SE’s aren’t always right; in fact, I used to be an SE and I’ll admit to being wrong on several occasions. The problem with the Account Manager/SE arrangement is that the two primary contacts the end user is engaged with have little, if any, real-world field experience. Their job is to sell licenses and be generalists; they have neither the time nor the motivation to be specialists with in-depth product knowledge gained by sweating it out in the trenches. I can tell you first hand that most SE’s work with the products they promote only in lab environments and have very little time for problem solving or immersive knowledge. I humbly admit to getting much of my knowledge during my SE days from product documentation and lab trials; I know for a fact that this is how it’s usually done.

Before all my SE friends flame me to death, understand that I’m not pointing fingers; it’s not your job to know this stuff, it’s my job - that’s why you sell the product and I make it sing and dance. Unfortunately, the client takes the SE’s words as gospel. On those rare occassions where the SE gets it wrong, I’m in a no-win situation - I have to tell the client that the solution is not going to work. There is no way to overcome the client’s response of “Well, that’s how Microsoft/Oracle/Cisco/IBM/Whomever said to do it” unless you have a long-standing relationship with that client. I can’t afford to nod my head and go along with it just to get the gig – not only will it destroy my credibility with the client and eliminate any chance to do business with them again, it also means that I won’t be able to use that project as a reference (and we consultants live and die by our references).

So if you’re a consultant caught in a similar situation, what do you do? In my mind, there’s no question. You politely and respectfully tell the client why, based on your experience and knowledge, you think what they’ve been told is wrong. You also preface it by saying that you yourself may be wrong and there’s only one way to find out for sure - test the recommendations to see if they work. But you can’t dance around the subject or equivocate; doing so will eventually end your consulting career. You probably won’t get the assignment, but you will have a clear conscience and, when the client does try to implement the misguided suggestions and fails, your stock will go way, way up (no, they won’t call you in to fix it, but they might call you for the next project - just be sure to avoid the irresistable urge to say “I told you so”).

Thursday, January 05, 2006

The Great Metadata Debate

Dustin Miller kicked over the anthill when he ranted against subfolders in document libraries. Bil Simser concurs and stirred up some more dust with his post on the subject. Of course, some folks take exception to all this, preferring to do things the old-fashioned way, but the real question is: what good are subfolders, anyway? Do they help us categorize information? No, they do not. Do they help users find documents easier? Absolutely not. Are they intuitive? Not really. Do users know what to do with them? Ah, and there's the rub - users are comfortable with folders and they know how to use them. Now ain't that a bummer???

While Dustin and Bil are most certainly correct - metadata is by far the best way to categorize and display information in SharePoint - it turns out that there's a lot to be said for giving users something they're used to amidst a sea of change. Think about it for a minute: we toss around terms like 'metadata', 'lists', 'views', 'libraries', 'categories', 'content', 'areas', etc. like they're second nature to everyone but the truth is they only mean something to US. Your average user doesn't understand any of this and, what's worse, they don't even care. Here's a neat little trick - want to immediately turn a room full of professionals into a group of slack-jawed zombies? Use the word 'metadata' three times in one minute and see what happens. They instantly tune you out. I've seen it happen many times.

It may just be that we're asking people to digest more than they have an appetite for. Not only do they have to get used to all this SharePoint mumbo-jumbo but now they have to give up their folders too? For Pete's sake, it took them five years to learn what a network share is and now everything goes back into one directory? I swear I can hear the gears in their brains grinding to a halt when I get to this portion of the training.

Rarely do we have time to fully train (and re-train) every user before the new portal goes live. And even if we did, it's just too much for them to absorb. So we make a judgement call and weigh the options - do we have all these nice little categories that please our analytical minds or do we have immediately productive users? Every client I've ever had opts for the latter and rightly so - no organization can afford that much disruption.

Here's the other problem with metadata that nobody's talking about: it takes a lot of time to make it work right. Not only do we have to decide upon our categories but then we have to create lookups, add list definitions, modify views, group, sort, filter and generally yank, pull, twist, poke and wiggle until it all looks right. Then we need another library to do the same thing - but just a little bit different, of course - and we're at it again, like an army of SharePoint worker bees, buzzing around our little libraries being busy, busy, busy. Meanwhile the users are putting documents back into folders on the network 'cause that's what they know and all this SharePoint stuff is just too hard.

So what do we do? WE know metadata is good but user's don't. WE know it streamlines indexing and retrieval but they could care less. WE know folder structures are the worst way to organize information since, well, folder structures but nobody's listening. A bit of the ol' rock-and-a-hard-place, isn't it?

Well, here's an idea. Give 'em both. Give your users metadata AND folders. Let 'em store stuff the way they always have (at least for now) but also enforce metadata rules. Create standard list definitions and views for each document library that contain all the basic metadata fields that map directly to Word/Excel/etc. so they can fill out the fields in Office and don't have to fiddle with web forms (if you haven't done that yet, you're missing the boat. Read this immediately). Customize the base defs/views only when you have to. Let users upload docs into whatever folder structure they desire until it comes time to ween them off; say six months, or even a year, when they can hear 'metadata' without their eyes glazing over. You can always move the docs out of folders and into the base library later on (I know, I know, some links will be broken but your views will still be intact).

In other words, feed them the elephant one bite at a time so they get used to the taste then invite them to the banquet. Users will be much happier and they'll actually stick with it since the new has now become the old. You'll still have a contingent of naysayers who'll put up a fight when it's time to yank their beloved folders out but by that time they'll be a distinct minority instead of a vocal majority. It'll save you a lot of headaches and them a lot of frustration. That's a win-win if I ever heard one.

UPDATE: For more on metadata and how to use it, see Ian Morrish's post on Sharepoint and metadata.

UPDATE 2: Daniel McPherson links back to an older post on the same subject. His real-life example is dead on.

Extreme Sharepoint Design: Modifying User-Defined Web Part Pages

User-defined web part pages allow web designers and portal members to create isolated pages with the same basic functionality as a standard area or site page. Because they are stored in document libraries instead of the area or site collection hierarchy, they can be created, deleted, and modified without affecting portal navigation, taxonomy or search results. They serve as an effective, low-impact method for enabling user creativity.

Customizing user-defined web part pages is not quite as tricky as overhauling a complete site definition but they do present the designer with a few unique challenges. For one thing, there are several types in every definition and each one is slightly different. For another, they have a few built-in limitations that will cause problems if you don't know what to watch out for. Coordinating the look and feel of these pages with the overall portal design will improve consistency and encourage users to create their own pages without impacting the portal architecture.

User-defined web part pages are stored in the DOCTEMP\SMARTPGS directory of each site definition, named in ascending numerical order (SPSTD1.ASPX, SPSTD2.ASPX, and so on). Each numbered file is directly related to an option in the Web Part Page Creation Wizard (SPCF.ASPX) section titled "Layout". The 'Choose a Layout Template' select box contains eight options for page layout, from a simple, single-column design to a complete, multi-zone web part page. Should you choose to edit Web Part Page Creation wizard page to add or remove items to/from this list, you will notice that the options are out of order in the select box code (line 251 of SPCF.ASPX):

<SELECT id="onetidWebPartPageTemplate" name="WebPartPageTemplate" size="8" onchange="DoTemplateOptionChange()">
<OPTION value="1">Full Page, Vertical</OPTION>
<OPTION value="3">Header, Left Column, Body</OPTION>
<OPTION value="4">Header, Right Column, Body</OPTION>
<OPTION value="2" selected="true">Header, Footer, 3 Columns</OPTION>
<OPTION value="5">Header, Footer, 2 Columns, 4 Rows</OPTION>
<OPTION value="6">Header, Footer, 4 Columns, Top Row</OPTION>
<OPTION value="7">Left Column, Header, Footer, Top Row, 3 Columns</OPTION>
<OPTION value="8">Right Column, Header, Footer, Top Row, 3 Columns</OPTION>
</SELECT>

The options relate to each page in the site definition as follows:

Option 1 -> spstd1.aspx -> Full Page, Vertical
Option 2 -> spstd3.aspx -> Header, Left Column, Body
Option 3 -> spstd4.aspx -> Header, Right Column, Body
Option 4 -> spstd2.aspx -> Header, Footer, 3 Columns
Option 5 -> spstd5.aspx -> Header, Footer, 2 Columns, 4 Rows
Option 6 -> spstd6.aspx -> Header, Footer, 4 Columns, Top Row
Option 7 -> spstd7.aspx -> Left Column, Header, Footer, Top Row, 3 Columns
Option 8 -> spstd8.aspx -> Right Column, Header, Footer, Top Row, 3 Columns

In addition, each option has an animated GIF of the same name associated with it that provides a thumbnail view of the page design. These images are located in the 60\TEMPLATES\LAYOUTS\1033 directory. Display of the thumbnails is controlled by the following script at the top of SPCF.ASPX:

function DoTemplateOptionChange()
{
var index = document.frmWebPage.WebPartPageTemplate.selectedIndex;
document.frmWebPage.PreviewImage.src = strImagePath + "spstd" + document.frmWebPage.WebPartPageTemplate.options[index].value + ".gif";
document.frmWebPage.PreviewImage.alt = document.frmWebPage.WebPartPageTemplate.options[index].text;
}

These images may be replaced with a custom animated gif that reflects the new page design or directed to another file name by editing the DoTemplateOptionChange() function.

Modifying the pages themselves is done in much the same manner as any other definition file - start with the default code and add or remove tags and HTML code as necessary - but there are a few issues to bear in mind when working with web part pages:

1. Web part zones in the page body (excluding the TitleBar zone; see below) are contained within a specific set of table cells which are referenced by a script that determines whether or not to display the cell based on it's contents (or, more accurately, the lack thereof). To recreate this functionality, be sure to place your web part zones inside the following cell:

<td id="_invisibleIfEmpty" name="_invisibleIfEmpty" valign="top" width="100%">

It is also necessary to include the following script somewhere on the page (the default location is just after the closing row tag in the parent table for the web part zones):

<script language="javascript">if(typeof(MSOLayout_MakeInvisibleIfEmpty) == "function") {MSOLayout_MakeInvisibleIfEmpty();}</script>

2. By default, the TitleBarWebPart is added to each web part page when it is rendered. This web part displays the page title and 'Modify Shared Page' menu link. This web part is NOT specified in any SCHEMA.XML file and cannot be disabled. Furthermore, it's target is the TitleBar zone and this zone must exist on the page or an error will occur after page creation. The zone can be located anywhere on the page (it does not have to exist in the "_invisibleIfEmpty" table cell). To hide it from view, it can be placed within a container DIV whose 'display' style is set to 'none', but doing so will require the addition of the Settings Link control (<WebPartPages:SettingsLink runat="server" />) in the title area.

3. If the portal design incorporates custom menus, those menus changes will cascade down to the web part pages. Incorporate any definition-specific menu options into the corresponding web part pages and remove any elements with localized dependencies (such as <SharePoint:RelatedTasks>, which depends upon the <Toolbar Type="RelatedTasks"> section in SCHEMA.XML) or context-sensitive options.

4. Web part pages in each definition are similar but not exactly the same. Take note of the different controls used in portal definition pages and STS definition pages; for example, pages in SPSPERS use <SPWC:PersonalSpaceNavigation> while pages in STS use <Sharepoint:Navigation>. Similarly, the HTML layout code may change from page to page, with DIV's, Tables, and other elements in unusual locations. As with any site definition modifications, when copying and pasting code be aware of the differing page registrations for each definition type and any tags which that definition relies upon for proper page rendering (like <SPSWC:PersonalSpaceNavigation runat="server" /> on personal site pages).

To implement web part page modifications, simply copy the modified files to the target server(s). Since there are no XML files associated with this page type, changes will be seen immediately without having to reset IIS.

UPDATE: Dennis has a great post on adding your own custom templates to the 'Create' page in SPS/WSS.

The Blog Editor Blues

Riddle me this: Why is it so hard to find a blog editor that does everything most bloggers want in a single package? After fiddling for weeks with every editor out there I’m ready to pull my hair out by the roots. Some give you decent editing options but weak post management. Others are good at managing previous posts but don’t have nearly enough formatting options for new posts. Some are good at text, others at HTML. Do the people that develop these apps actually spend any time managing a blog? I’m thinking not.

Maybe I’m asking for too much. Here’s my list of requirements:

  1. Consistent formatting - A paragraph tag should be a paragraph tag no matter what. For some reason every editor handles tags differently; what looks right in one rich text designer looks terrible in Blogger and then gets even further garbled by Feedburner. Why can’t HTML just be HTML?

  2. Automatic Text Replacement - Is it really so hard to catch a less than/greather than symbol and replace it with properly encoded chracters while I’m typing or as soon as I cut and paste? We can figure out how to turn a computer into a virtual Bobby Fischer but we can’t get on-the-fly replacement to work? What the heck am I missing here?

  3. Post Status Handling - If I mark something draft that means I want it to be a draft when it’s uploaded not a regular post. When I switch it from draft to publish status it should post immediately without further action on my part.

  4. Outlook-Style View - I should be able to see previous posts in a pane on the left and the body of the post on the right. That way I can switch back and forth between posts without having a bunch of windows open.

  5. Search - I’m forever linking back to previous posts and looking for information. I should be able to search those posts to find what I want and link to it with a single click. Speaking of...

  6. Link URLs - Linking to posts should be easy; a single click and I’m done. The editor should insert the proper permalink from the blog address. This must be part of the same rocket science as text replacement because it doesn’t work right in any editor. I always seem to end up with some goofy address that has no bearing on reality. What gives?

  7. Tags and Keywords - I want to set up a list of keywords and have the editor automatically catch those words in my post and insert the proper Technorati tags. No further effort on my part required. When I tag a word manually, the editor should find subsequent instances of that word and insert the same tag on it’s own.

This post is being written in Anconia RocketPost, which does a fair job but won’t replace my text on the fly (even though it says it will), doesn’t have a split-pane view, doesn’t handle post status properly (even though the options are there) and still garbles up my HTML between editing and posting. I’ve also tried BlogJet, w.Bloggar, Quamana and Ecto, which all fall short in various areas.

So I’m putting out a plea to the community at large. What do you use? Have you found anything that meets all these requirements? Am I just in outer space or what? Leave a comment and steer me in the right direction...

Wednesday, January 04, 2006

SharePoint RPC Methods

I was browsing through Heather's list of SharePoint resources when I found this link to an RPC method that I was unaware of. That led to this article that documents the various RPC methods and provides even more links to other information.

If I'm not mistaken, isn't this just the sort of "associative trail" that Vannevar Bush had in mind all along???

UPDATE: Bil Simser has a great post on this topic that is a must read. Go check it out!

Top Ten Tricks for Customizing SharePoint

In the spirit of helping new SharePointers along (see this post from Bil and this one from yours truly), here's a Top Ten list to start the New Year off on the right foot. For anyone about to dive into heavy SharePoint customization, this is a good list to keep handy (or to use for lining your cat's litter box, whichever you find more appropriate).

1. Simple HTML
Keep your HTML layout code as simple as possible. Use the minimum number of formatting elements (DIV’s, SPANs, Tables, etc.). SharePoint creates a tremendous amount of extraneous code at runtime; the less you add, the less chance for something unexpected to happen. Also, you’ll be cutting and pasting a LOT of code; fewer lines means fewer mistakes.

2. User Controls
Reuse as much code as possible by placing repetitious elements into user controls. Rather than repeating the layout code that defines web part zones and code areas on page after page, place it in an ASCX file, register the file location at the top of the page, and reference it in the page body. This creates a template-like effect for site definition pages in which you only have to modify one file to have a global effect. An added benefit is that code which cannot be executed within presentation files can be executed within a user control.

3. Custom User Menus
SharePoint menus take up a great deal of valuable screen real estate. There’s nothing magical about the left-hand navigation area; extract the menu elements and place them into collapsing DIV’s or pop-outs. While they’ll never be perfect, a basic set of menu layouts can free up 125 – 300 pixels of screen width. Place them in user controls to simplify maintenance.

4. Nested Style Sheets
SharePoint style sheets are a confusing maze of endless CSS code. Nest common code elements in your custom style sheets just like you would with HTML; create parent styles, indent each child style, and keep everything together in logical groupings. Copy existing styles from OWS.CSS and SPS.CSS into your custom sheet to overwrite the defaults and maintain compatibility.

5. Minimal Site Definitions
There are few occasions where more than one or two custom site definitions are necessary (in addition to the required SPS, SPSMSITE, SPSPERS, SPSSITES and STS, all of which can be replaced with a custom definition by modifying the WEBTEMP files). Each definition exponentially increases the amount of customization and future maintenance. Use the bare minimum number of definitions to meet the requirements.

6. Server Controls
Custom code elements that do not require user manipulation should be implemented as server controls instead of web parts. The layout is easier to design with fewer web part zones, the code is much more compact, and render times are much faster. Store them in the /Bin directory along with the user controls for layout.

7. Preserve Zone Names
Some functions, such as ‘Edit in DataSheet’ require a specific zone to be present on the page. To avoid erratic behavior, preserve the default zone names whenever possible but change their location to meet your requirements. This also reduces the amount of edits to the various SCHEMA.XML files.

8. Comments Before Deletions
Before deleting existing code, comment it out and test it with your modifications. Once you have a working page, go back and delete the extraneous elements one by one. There are some pages that absolutely must have certain elements in place – even if they’re hidden - or they won’t render properly. You’ll save yourself a great deal of frustration by working backwards through commented code than trying to add it back in later.

9. Assumption = Frustration
Never assume that the modifications you make in one definition will work in another. This is especially true of SPS and its deviations; the root portal definition is quite different from the subarea definitions. Diff the original files extensively before copying changes to a new definition. This rule applies in spades to administration pages, where there are multiple shared code structures and many one-off files.

10. Make CAML Your Friend
Much of what drives SharePoint lives in ONET.XML and SCHEMA.XML. The more extensive the modifications, the more you’ll need to work with these files. Learn the ins and outs of CAML and how to tweak it to meet your needs. Although at first intimidating, it’s nothing more than a structured XML superset. Begin by adding list definitions and move from there into creating custom lists and mastering views.

Happy SharePointing!!!