Tuesday, November 29, 2005

To Brand or Not to Brand...What Was the Question?

While I was pontificating on the need for improved customization in SharePoint v.Next, Andy May suggests that it might be a good idea to find out if your client really wants to tackle the task of branding their portal. A fair question, and one that my clients have answered in multiple ways, from nothing more than an altered site logo to full, file-by-file customization of definitions and templates. As Heather points out, it's not that difficult to brand a portal implementation if you leave the underlying architecture definitions alone.

In my mind, there are three distinct types of scenarios:

1) Stock Portal - No branding or customization required. If you have limited resources or need to focus your resources elsewhere, such as application development or training, this might be the best option. This scenario is often chosen by those with little exposure to Intranet/Portal applications who just need a quick and affordable solution.

Example:




2) Branding - Applying a custom logo, colors, backgrounds, borders, fonts, buttons and other visual elements can be done in a few days from scratch or a few hours if you have a CSS template to work from. Assuming that time and resources are available, branding is an effective way to reinforce a corporate identity and create continuity with other line-of-business applications. Organizations with existing Intranets or portal-like applications often choose this route as it is both affordable and relatively painless. It is also a very good way to learn more about how SharePoint works behind the scenes.

Example:




3) Customization - Let there be no doubt: full portal customization is difficult, time consuming, expensive, and requires a high degree of skill and patience. Only clients who have deployed extensive portal solutions in the past request this level of modification, and rightly so; they have a solid understanding of the cost and risks involved. At best, a complete portal customization can be done in 30 days (I've done it and it was no picnic, believe me); at worst, it could take several months. And that's assuming that you're well-versed in all the mysteries of SharePoint; a neophyte who has to learn on-the-fly may never make it out of SharePoint Customization Hell alive (figuratively speaking, of course, and thanks to Heather for the highly appropriate terminology).

Example:





In the final analysis, it is up to you as the consultant or subject matter expert to explain these options to your client (or decision makers if you are part of the organization), make sure they understand the risk/reward ratio, and provide a realistic estimate of time and cost. One of the most common mistakes I see when consulting with clients regarding customization is the perception that SharePoint is limited in what you can do with the user interface. True, there are certain parameters which influence what the final outcome will be, but the truth is that there are very few things you can do with any web application that you cannot do with SharePoint.

I've discovered that even those who have worked with SharePoint for a good while are unaware of how extensively the product can be customized; not surprising, considering that most people probably give up after fighting with multiple site definitions, scads of similar-but-slightly-different list pages, CAML, never-ending XML files and a confusing maze of CSS. I don't blame 'em - it's enough to give anyone a headache (I keep an emergency supply of Advil on hand at all times).

Personally, I prefer a branded or fully-customized implementation over the stock look-and-feel simply from a business perspective. You wouldn't create an application or web site for a client without taking their corporate identity into consideration; the same applies to a portal implementation - you shouldn't avoid it just because SharePoint makes it more difficult than it really ought to be.

Here are a few tips to ease the pain:

1. Lean which CSS classes need to be modified to achieve your branding objectives and place them into a separate file, then use the custom CSS setting in portal admin to implement your alternate style sheets.

2. When overriding the default CSS classes, create a consistent structure that makes it easier to customize the files in the future (I like to nest related classes and define common elements, such as default fonts and colors, at the top of the file).

3. Once you've established the bare minimum required for branding a portal, use that CSS file as a template so you can apply it to subsequent implementations.

4. Study the Site Definition structures for patterns. Many of the files have similar code elements but for a few variances; learn what they are and where they occur. Once you have created a working definition, copying the files to new defs is mostly search-and-replace (your life will be much simpler with good diff and HTML search/replace tools; I suggest Beyond Compare and Search & Replace 98).

5. Do the same for admin pages in the /layouts/1033 directory. Take note of what works where (some pages are WSS only; others SPS; many are both). Learn which pages alternateheader.aspx works on and what it's limitations are.

6. Make extensive use of user controls (ascx pages). Like the include files of old, user controls give you the capability to modularize your definitions, sharing common code structures throughout the portal. All they require is a simple code registration in the header to tell the page where to find the file and what it's called. This can save you an immense amount of time and frustration. And, best of all, user controls allow you to execute code that may be blocked within certain files (did I mention alternateheader.aspx yet?).

7. Learn which web controls (<SPSWC:> elements) pages require and which can be deleted. Most pages can simply be wiped out and replaced with your own code but some, like txtlstvw.aspx, require fixed page elements in order to render properly (here's a hint: just comment them out, change the ID values, then substitute your own custom elements with the original ID's). Many Admin pages require the PortalHeader element but that doesn't mean you have to display it - just hide that pesky critter and go on about your business.

8. Watch those registrations! Some pages that look the same on the surface use different components to achieve similar results. Check the registrations at the top of the page to make sure that you have the right elements on the page. If you make extensive use of inline code blocks in user controls or admin pages be sure to include Microsoft.SharePoint.WebControls or the code will fail.

9. Look closely at the XML configuration pages. CAML is nothing more than a fancy superset of XML; anyone with a little bit of coding background can quickly determine what the programmer was trying to achieve and duplicate/alter it accordingly.

10. Get the SPS SDK and use it. It doesn't cover everything but there's a lot of good information in there that will help you out when you get into a bind.

11. Don't be afraid to break something! Test your changes extensively in an isolated sandbox that you can wipe out if things to awry. Keep a full copy of the original 60 hive handy to replace any modifications that don't work. Modify in small increments and test after each change, then proceed to more full-scale alterations.

12. Ask for help. There's no better resource at your fingertips than the SharePoint community. Yes, we all have day jobs, but we're happy to lend a hand if you need us. It takes time to maintain a blog or answer newsgroup postings; if we didn't care, we wouldn't do it. If we don't know the answer we can probably point you in the right direction.


Good luck!

Monday, November 28, 2005

List-Level Permissions in SharePoint Portal Server

WARNING! WARNING! WARNING!

This may just be the most unsupported tip I have ever posted, and for someone who is known for finding creative ways to enable or implement features that often fall into the 'unsupported' category, that's saying quite a bit. I struggled with whether or not to post this for a few days but in the end I decided that the value outweighs the cost. You're all big boys and girls so you can make your own decisions on whether or not to implement this solution. If you do, you are completely on your own - although I've tested it in at least three scenarios without incident, that is no guarantee that it won't completely crash your portal implementation. So...

READ ON AT YOUR OWN RISK!!!

Now that the disclaimers are out of the way (this is serious - don't do this if you're uncertain of how it will effect your portal), let's get down to business. One of the most frustrating restrictions in SPS is the inability to assign list-level permissions to individual lists. Unlike WSS, SPS lists inherit permissions from the portal area they live in. This means that you must create a new subarea in order to implement individual list ACL's.

This limitation is enforced by the ExternalSecurityProvider value specified in the ONET.XML file for each site definition. According to the SDK, this COM GUID, which is static for all SPS implementations, defines the security context for the search crawler. Strangely enough, it is also referenced on line 522 of the listedit.aspx file, which obviously has nothing to do with search and indexing. When present, the 'Change Permissions for this List' link is hidden; when removed, it is displayed. By commenting out the associated 'if' statement (lines 522 through 537), the 'Change permissions...' link becomes active for all lists; clicking on it takes the user to the Change Permissions page (shropt.aspx).

Unfortunately, disabling the SecurityProvider check is not enough to enable list-level permissions. As one will quickly discover, clicking on the 'Add Users' button on any subarea (but not the root SPS area) will lead to an endless authentication loop. This confounded me as it seemed to work fine in the SPS definition but nowhere else. When the same issue came up with Jan Tielens' UserAlerts web part and some custom web parts a colleague was developing, I realized they were all related.

The difference is due to a small change to the ExternalSecurityProvider GUID in the ONET.XML file of the SPS site definition and all other definitions (STS, you will note, does not have such a setting). At the bottom of SPS ONET.XML file you will find the following entry:

<Components> <FileDialogPostProcessor ID="C6659361-1625-4746-931C-36014B146679" /> <ExternalSecurityProvider ID="A373E6A7-7A87-11D3-B1C1-00C04F68155C" Type="Microsoft.SharePoint.Portal;Microsoft.SharePoint.Portal.SiteData.
CategoryWebSecurityProvider" /></Components>

Look closely at the ExternalSecurityProvider ID value. For most of the other Site Definitions the first octet ends in an '8' instead of '7' (i.e. A373E6A8 instead of A373E6A7). Looking into the WEBS table of the _SITE database, I discovered that this GUID is stored in the SecurityProvider column for each area (interestingly, bucket areas have a '9' at the end of the first octect instead of a '7' or an '8'). Apparently, whenever the DLL retrieves this value from the DB, if it does not match a certain value range, access to the function being called is not allowed, which results in the authentication loop. At first, I assumed that this only applied to list permissions as listedit.aspx is the only file in which the ExternalSecurityProvider setting is referenced; however, I discovered that several object-model queries (user.alerts and user.roles) also share the same restrictions. Any code that accesses these methods from a portal subarea will fail.

The solution to these problems is simple yet potentially dangerous (if you are still reading now would be a good time to bail out). It involves modifying the listedit.aspx page (not supported), changing the GUID value in the ONET.XML file for your custom site definition (OK as far as I can tell - it's your definition, after all), and, if any areas have already been created, updating the WEBS table with the new GUID value (definitely not supported).
For the bold and brave, here's the procedure:

1. Modify the 'listedit.aspx' file by commenting out (//) lines 522 - 537, as follows:

// if (!spWeb.HasExternalSecurityProvider)// {%> <TR> <TD> </TD> <TD class=ms-propertysheet colspan=4><IMG SRC="/_layouts/images/rect.gif" alt=""> <A ID=onetidListEdit7 target=_self <% if (iBaseType == SPBaseType.DocumentLibrary) { %> HREF="ShrOpt.aspx?obj=<%SPEncode.WriteUrlEncode(Response, spList.ID.ToString("B").ToUpper());%>,doclib" <% } else { %> HREF="ShrOpt.aspx?obj=<%SPEncode.WriteUrlEncode(Response, spList.ID.ToString("B").ToUpper());%>,list" <% } %> ><% switch (iBaseType) { case SPBaseType.DocumentLibrary: if (SPListTemplateType.PictureLibrary == iServerTemplate) { %>Change permissions for this picture library<% } else if (SPListTemplateType.XMLForm == iServerTemplate) { %>Change permissions for this form library<% } else if (SPListTemplateType.ListTemplateCatalog == iServerTemplate SPListTemplateType.WebTemplateCatalog == iServerTemplate SPListTemplateType.WebPartCatalog == iServerTemplate) { %>Change permissions for this gallery<% } else { %>Change permissions for this document library<% } break; case SPBaseType.DiscussionBoard: %>Change permissions for this discussion board<% break; case SPBaseType.Survey: %>Change permissions for this survey<% break; default:%>Change permissions for this list<% break; }%></A></TD></TR><%// }

2. Change the first octet of GUID value in ONET.XML file from 'A373E6A8' to 'A373E6A7', as follows:

<ExternalSecurityProvider ID="A373E6A7-7A87-11D3-B1C1-00C04F68155C" Type="Microsoft.SharePoint.Portal;Microsoft.SharePoint.Portal.SiteData.
CategoryWebSecurityProvider" />

3. Run the following SQL statement on the SITE database in SQL Query Analyzer:

UPDATE Webs SET SecurityProvider = '{A373E6A7-7A87-11D3-B1C1-00C04F68155C}' WHERE SecurityProvider = '{A373E6A8-7A87-11D3-B1C1-00C04F68155C}'

That's it. You now have list-level permissions in portal subareas. As I mentioned, this may have unintended consequences; this value may by used elsewhere and cause something that was working to break or disable some dependent functionality. In my test scenarios I was unable to find any negative effects but that doesn't mean they don't exist. Try it at your own (considerable) risk.

BTW, if anyone from Microsoft reads this and knows what effect a change in the SecurityProvider GUID might have on portal operation, please enlighten us as it is not documented anywhere that I could find.

As an aside, I am certain that this post will officially exclude me from MVP consideration for the rest of my life ;-)

SharePoint v.Next Upgrade Issues

Arpan Shah has a good post on things to consider in preparation for the upgrade to SPS/WSS 3.0. I generally make a concerted effort to toe the line with regards to guidelines from Microsoft but when something is seriously out of whack I have to take exception. Two of the 'Golden Rules' of SharePoint customization that Arpan repeats in his post have me seriously concerned that Microsoft is not taking into account their customer's desire to fully customize SPS in the next release; namely, 1) Database access, and 2) File/Definition modifications. As Arpan states:

1. Don't touch the database. Modifying is a big no-no... reading it -- there's no guarantee that the schema will be the same. If you want to ensure a smooth upgrade, don't touch it or use partner technologies that modify the database.

2. Don't modify out of the box files/directories/stylesheets, et cetera. Whenever possible, you should be creating copies and then modifying vs. modifying the out of the box files. Service Packs or future versions can overwrite files and you can lose your customizations. Net/net: follow customization guidelines!

This is all well and good but both of these 'rules' completely ignore the realities of full-scale customization. First, I defy you to create a portal-wide, collapsible, dynamic navigation menu (a la MSDN menus) or a nested drop-down navigation bar that includes both SPS areas and WSS sites without reading from the database. Sure, you can cobble together an object-model server control but it will be a) V-E-R-Y S-L-O-W and b) very buggy. Not to mention the fact that you can't make the association between WSS sites and SPS areas without reading from the WEBS and SITES tables. I completely support the notion that modifying the database is BAD IDEA but not being allowed to read from it overly restricts development and customization.

Second, you absolutely cannot deploy a fully branded and customized portal solution without modifying the SPS, SPSPERS, SPSMSITE, and SPSSITES site definitions. Add WSS sites and you must also customize the STS definition (although you can work around that limitation by getting fancy with the WEBTEMP.XML files). What good are stand-alone area customizations if they don't integrate with the rest of the portal? We're talking about customizations far beyond portalheader.aspx and alternateheader.aspx - full page layout and design changes cannot be achieved without editing the core definitions. (NOTE: You can modify WEBTEMPSPS.XML and replace the default definitions with custom definitions using the same ID but it doesn't always work right, especially when replacing the SPS definition, and besides, according to the guidelines, we're not supposed to modify the base XML files either).

Third, administration pages are a unique animal unto themselves. At last count I have discovered at least half a dozen shared code structures just for admin page headers (sorry to disappoint, but alternateheader.aspx only works in about a third of those pages, and it's functionality is limited at best) and a bunch of stand-alone configurations. Many don't include references to custom CSS files or all the code registrations necessary for including server controls (you do want a common navigation scheme at the top of ALL your pages, don't you?). Remember that many of these pages are accessed regularly by portal users - spsviewlsts, lstman, aclinv, catman, create, listedit, and so on - so modifying them is required if you wish to maintain any sort of continuity in portal design.

I understand that customization in the current product is tricky at best but v.Next is supposed to address that issue, is it not? I thought so but Arpan's post makes me wonder if that will be the case. Word to the mother ship - CUSTOMERS DEMAND CUSTOMIZATION!!! Neglect the ability to customize the product and customer satisfaction will plummet. I sincerely hope this requirement has been taken into consideration and the final release will take full advantage of .NET 2.0 features to provide scalable, extensible customization options without restricting the customer to a less-than-desireable mish-mash of 'works here but doesn't work there' compromises.

Don't get me wrong - SharePoint is a great product and I appreciate the customization flexibility that Microsoft has given us (even if some of it is inadvertent). I also appreciate the wisdom from on high provided by Arpan, Fitz, Maurice, and others. I just hope that the lessons of v2 influence the features of v3 inasmuch as customization is no longer an option but a requirement.

For those of you that have already done extensive customization to your portal deployment, here are some practical suggestions to prepare for the v.Next upgrade:

1. Insure that you have copies of all the original, unaltered files, definitions and directory structures.
2. Make a copy of all modified files, definitions and directories.
3. Make a copy of all database additions, such as stored procedures, logins and custom indexes.
4. Prior to upgrading, restore the original files/defs/dirs and remove any custom CSS files, images, etc. from the 60 hive.
5. Remove all database additions.
6. Perform the upgrade to a test portal.
7. Determine what impact the new changes have on your customization scheme and modify/redeploy accordingly (many of the hard-coded mods my no longer be necessary as Master Pages will replace much of the file-by-file alterations necessary in the current version).
8. Revise your database additions to account for any schema changes and redeploy.
9. Test and modify your web parts and server controls (especially those that read from the DB).
10. Test, test, and test again, then downgrade the live portal deployment to a basic install, upgrade to the new version, and deploy your customized portal elements.

Bear in mind that these are just suggestions - without having the new version to test against there is no way of knowing what the actual procedure will be. The more extensive the customizations the sooner you should begin testing and planning the upgrade to v.Next for your clients/organization.

Wednesday, November 23, 2005

Extreme SharePoint Design: Custom User Menus, Part 2

In a previous post, I described at length the process for creating custom user menus in SharePoint. In the associated code samples, I neglected to account for windowed controls that might obscure the menu drop-downs on a page. As anyone who has designed extensively for IE knows, windowed controls (such as ActiveX or Select boxes) ignore the 'z-index' property assigned to DOM elements and take precedence in the display; that is, they are drawn on top of all other controls. If you use the hidden DIV method I outlined there are some instances, such as opening a document library in datasheet view, where the menu options disappear behind the web part.

There is no direct solution for this problem but there is a workaround using IFRAMEs and javascript. First, let's re-familiarize ourselves with the code that draws that the hidden div and the script that activates it when the user clicks the menu button:
Page Code (in DEFAULT.ASPX or a custom user control):

<td valign="top" align="right" nowrap onclick="SwitchMenu('ActionsMenu')" class="spsWPZ_ActionsMenu_Header">Actions<img src="/_layouts/images/menudark.gif" align="absbottom" > <div id="ActionsMenu" onmouseover="this.style.display='inline'" onmouseout="this.style.display='none'" class="spsWPZ_PageHeaderMenu_Div" > <table width="100%" cellpadding="0" cellspacing="0" border="0" class="spsWPZ_PageHeaderMenu"> <!-- Toolbar Elements Here --> </table> </div></td>

Javascript (in the page header or OWS.JS):

function SwitchMenu(obj){var el = document.getElementById(obj);var parent = el.parentElement;var x = getPageOffsetLeft(parent);var y = getPageOffsetTop(parent) + parent.offsetHeight;var p = parent.offsetWidth; if(el.style.display == "inline") { el.style.left = (x - (175 - p)) + "px"; el.style.top = (y - 7) + "px"; el.style.display = "none"; } else { el.style.left = (x - (175 - p)) + "px"; el.style.top = (y - 7) + "px"; el.style.display = "inline"; }}

The code above displays a table cell ('Actions') that acts as a menu button and creates a DIV element ('ActionsMenu') that is hidden when the page loads. When the user clicks within the table cell the SwitchMenu function is called, which activates the ActionsMenu DIV, positions it below the cell and displays it on the page. The onMouseOver and onMouseOut events cause the DIV to disappear when the user moves the mouse outside the DIV boundary, mimicking the behavior of a regular Windows menu.

This works just fine until a windowed control is placed on the page that intersects with the ActionsMenu DIV, at which time the control will obscure the DIV, making it impossible to access the menu functions. In some cases, the page becomes unusable because all the operations ('Modify Settings and Columns', 'Edit Page', etc.) are hidden. To resolve this issue an IFRAME must be placed immediately below the ActionsMenu DIV that is the same width and height and exposed in response to the user click on the table cell.

First, create a hidden IFRAME within the ActionsMenu DIV and place it immediately before the content table as follows:

<div id="ActionsMenu" onmouseover="this.style.display='inline'" onmouseout="this.style.display='none'" class="spsWPZ_PageHeaderMenu_Div" > <IFRAME style="display: none;" id="ActionsMenuFrame" name="ActionsMenuFrame" src="javascript:false;" frameBorder="0" scrolling="no" ></IFRAME> <table width="100%" cellpadding="0" cellspacing="0" border="0" class="spsWPZ_PageHeaderMenu"> <!-- Toolbar Elements Here --> </table></div>

The style of the IFRAME is set to "none" to keep it hidden until the DIV is exposed. The NAME and ID settings are important as these will be used in the SwitchMenu function later. The SRC property calls a dummy javascript instead of referencing a blank HTML file, which can lead to client-side security warnings in an HTTPS environment.

Next, update the SwitchMenu function with methods to display and position the IFRAME:

function SwitchMenu(obj){var el = document.getElementById(obj);var parent = el.parentElement;var x = getPageOffsetLeft(parent);var y = getPageOffsetTop(parent) + parent.offsetHeight;var p = parent.offsetWidth;var aFrame = document.getElementById('ActionsMenuFrame'); if(el.style.display == "inline") { el.style.left = (x - (175 - p)) + "px"; el.style.top = (y - 1) + "px"; el.style.display = "none"; } else { el.style.left = (x - (175 - p)) + "px"; el.style.top = (y - 1) + "px"; el.style.display = "inline"; aFrame.style.zIndex = el.style.zIndex - 1; aFrame.style.display = "inline"; aFrame.style.position = "absolute"; aFrame.style.top = "0px"; aFrame.style.left = "0px"; aFrame.style.height = el.offsetHeight; aFrame.style.width = "175px"; }}

The function now uses a variable called 'aFrame' to access the properties of the IFRAME('ActionsMenuFrame'). The IFRAME is then positioned one level below the DIV by setting the zIndex property. The display type is then changed to 'inline' and the IFRAME is set to the top and left position of the parent DIV. The most difficult part of positioning the IFRAME is matching the height of the parent object; because the ActionsMenu DIV does not have an explicit height setting (it expands or contracts based on the content in the child table), the el.style.Height value cannot be used; instead, the function uses the offsetHeight property, which is accessible once the control is drawn (which happens in the preceding IF...ELSE blocks).

The menu will now overlay all page controls, as IFRAME is a unique IE element that is aware of the zIndex values of both browser elements and windowed controls (the zIndex for the ActionsMenu DIV is set in a CSS file). The page will now render with the windowed controls on the bottom, then the IFRAME, then the DIV on top. This will prevent any ActiveX controls, select boxes, or other page elements from obscuring the menus and limiting usability.

Friday, November 11, 2005

Cracking Open STP Files

Todd Bleeker has a great post on manipulating data within STP files. Timely information, as I was just working on a similar problem the other day. Thanks, Todd!

Thursday, November 10, 2005

Changing the SharePoint Admin Password

Before installing SharePoint it is important to give some thought to the account that will be used as the portal administrator. Not only is the admin account referenced throughout the portal (area/site ownership, document metadata, list properties, etc.) but it's also used for many basic functions that are central to portal operation - connections to the configuration database, content crawling, application pool identity, and so on. Because the portal administrator must have complete and total control over the SharePoint server(s), a good practice would be to use an account specifically for this purpose that has limited rights elsewhere in the domain.

Assuming that you have followed this methodology in your portal deployment, the next obvious question is: What happens when you change the portal administrator password? Alas, this is a simple question with a not-so-simple answer. There are several steps required to successfully implement this change and they must be done in a specific order. Download the following article which outlines the scope and implications of modifying administrative account properties and defines a procedure for implementing changes.

NOTE: This procedure has been tested for accuracy but each deployment is different; if you run across any variations please post comments and I will update the document accordingly.

Modifying Administrative Account Properties (PDF)

Monday, November 07, 2005

Extreme SharePoint Design: Validating Area Titles

Most web-savvy tech types know better than to use "special" characters in URL fields - apostrophes, question marks, carets, ampersands, and the like. Unfortunately, this rule of thumb is lost on the average SharePoint user and an open text box with no validation is an invitation to wreak havoc on your carefully constructed portal navigation. IE will overlook most illegal characters but some third-party or custom developed navigational controls will not, so a good practice would be to discourage the use of symbols in Title and URL fields.

You can, of course, add big warnings to the admin pages warning against such malfeasance but we all know that the bigger the warning, the more often it is overlooked. So what to do? The best way to handle this situation is to check the user input against a list of disallowed characters and force text modifications before the field is posted. Fortunately, if your portal consists mostly of WSS sites, you've got it made - the WSS site creation form (scsignup.aspx) has built-in validation to prevent users from entering illegal characters in certain fields; however, if you make extensive use of SPS areas, the solution is not quite so simple. Here's how to replicate the WSS behavior in SPS:

First, create a script to check the user's input against your list of illegal characters, similar to the following:

<script>
function validateSiteName(ctlId)
{
var iChars = "!@#$%^&*()+=[]';,./{}\":<>?";
var ctlName = document.getElementById(ctlId) for (var i = 0; i < ctlName.value.length; i++)
{
if (iChars.indexOf(ctlName.value.charAt(i)) != -1)
{
alert ("The Title field contains special characters which are not allowed. Please remove them and try again.");
ctlName.focus();
return false;
}
}
}
</script>

This script defines the list of illegal characters (iChars), gets the ID of the input box (ctlName), then, if the text box isn't empty, steps through each character and matches it against the list. If a character matches one of the illegal characters, the script displays an alert box asking the user to remove the offending characters and returns the focus to the input field, preventing them from saving the form without fixing the problem.

Second, paste the script into the <HEAD> section of the area creation and modification pages (spnewcategory.aspx and speditcategory.aspx, respectively) or append the function to OWS.JS file (which is called from every page within the portal).

Third, call the script using the onBlur method from the form. Find the following code block on the page:

<SPSWC:InputFormTextBox
runat="server"
id="TextBoxTitle"
IsTextTrimmed = "true"
LabelTextLocId="SiteAdminCreateCategory_Title_Colon_Text" AccessKeyLocId="SiteAdminCreateCategory_Title_AccessKey"/>

Then add the onBlur event to the end:

<SPSWC:InputFormTextBox
runat="server"
id="TextBoxTitle"
IsTextTrimmed ="true"
LabelTextLocId="SiteAdminCreateCategory_Title_Colon_Text" AccessKeyLocId="SiteAdminCreateCategory_Title_AccessKey"
onBlur="validateSiteName(this.id);"/>

This will fire the validateSiteName function whenever the user clicks or tabs out of the input field.

Finally, save the modified pages to the 60\TEMPLATE\LAYOUTS\1033 directory and users will be unable to enter any illegal characters into the area title field, which is used by SPS to construct the bucketed URL, thereby preventing any incompatabilities with navigational tools and utilities.

Tuesday, November 01, 2005

MySite Permissions

The MySite site definition (SPSMSITE) is intended to provide only the 'Private' and 'Public' page views for a user's personal site; all other functionality (lists, doc libs, etc.) is handled by the Personal definition (SPSPERS). When customizing these definitions (if you want to provide MySite functionality, you have no choice but to customize the existing definition - I know it's not supported but it's there just isn't any other way), it is important to remember that SPSMSITE is a full definition, with the same base set of included lists as all other defs.

While there are no direct links in the GUI for working with MySite lists, users can add list web parts from the tool pane and, by default, modify the list contents. Since MySite content is global (personal site content is localized to the individual user account), any changes to MySite lists will show up for all users; not an ideal situation.

To work around this issue, change the MySite permissions for Members and Contributors. Use the following URL syntax to access the MySite security page (there is no 'Manage Security' link for this area):

http://%lt;server name%gt;/mysite/_layouts/1033/spcatsec.aspx

Check the Contributor and Member groups (and any others you wish to modify), click 'Edit', and uncheck the 'Add Items' right under the Select Rights section. This will prevent users from doing and end-run around list security by dropping list web parts onto the MySite pages and modifying the content.