27 January 2010

Custom Theme and Feature Stapling via WSP files

Looking to deploy a custom theme in a solution file? Here’s how to modify the SPThemes.xml file programmatically using Linq to XML. The only thing missing would be clean-up of sites using the theme upon uninstall.
http://blogs.msdn.com/ketaanhs/archive/2009/07/01/modifying-spthemes-xml-programmatically-to-deploy-new-themes-moss-2007-wss-3-0.aspx
Recently used this for a client along with feature stapling to deploy a custom theme and then force all newly created sites to use the theme. I used the WSPBuilder templates for VS2008 (I prefer these above the templates VsWSS).
Step 1: Create a WebApplication scoped feature to handle the FeatureStapling and create a SPFeatureReceiver for the feature to install the feature into the SPThemes file using the technique above.


<Feature xmlns="http://schemas.microsoft.com/sharepoint/"
         Creator="Chris Quick, Tribridge"
         Description="Forces default Client branding for all sites"
         Hidden="false"
         Id="9DEE24AC-1FF9-4fb3-AC07-2A0D9D616D99"
         Scope="WebApplication"
         Title="Client Default Branding"
         Version="1.0.0.0"
         ReceiverAssembly="Client.SharePoint.Branding, Version=1.0.0.0, Culture=neutral, PublicKeyToken=7622be71ccc3f186"
         ReceiverClass="Client.SharePoint.Branding.ClientThemeInstaller">
  <ElementManifests>
    <ElementManifest Location="elements.xml"/>
  </ElementManifests>
</Feature>

Step 2: Setup feature stapling in your ElementManifest file. Make sure the ID of the feature to staple is the ID of the feature that applies the branding (created next).

<Elements xmlns="http://schemas.microsoft.com/sharepoint/">
  <FeatureSiteTemplateAssociation Id="FA5FE9BA-8DCB-40c8-950B-517AC11FCC23" TemplateName="GLOBAL"/>
  <FeatureSiteTemplateAssociation Id="FA5FE9BA-8DCB-40c8-950B-517AC11FCC23" TemplateName="STS#1"/>
</Elements>

Step 3: Create another feature scoped to the Web that will have a feature receiver using a co-worker’s method of applying a theme.

<Feature xmlns="http://schemas.microsoft.com/sharepoint/"
         Creator="Chris Quick, Tribridge"
         Description="Applies Branding to New Sites for Client"
         Id="FA5FE9BA-8DCB-40c8-950B-517AC11FCC23"
         Hidden="False"
         Scope="Web"
         Title="Client Branding Receiver"
         Version="1.0.0.0"
         ReceiverAssembly="Client.SharePoint.Branding, Version=1.0.0.0, Culture=neutral, PublicKeyToken=7622be71ccc3f186"
         ReceiverClass="Client.SharePoint.Branding.ClientBrandFeatureReceiver">
  
</Feature>


using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.SharePoint;

namespace Client.SharePoint.Branding
{
    class ClientBrandFeatureReceiver : SPFeatureReceiver
    {
        public override void FeatureActivated(SPFeatureReceiverProperties properties)
        {
            SPWeb currentWeb = (SPWeb)properties.Feature.Parent;
            currentWeb.AllowUnsafeUpdates = true;
            currentWeb.ApplyTheme("Client");
            currentWeb.SiteLogoUrl = "/_layouts/images/Client/Client-logo.gif";
            currentWeb.Update();
            currentWeb.AllowUnsafeUpdates = false;
            currentWeb.Dispose();
        }

        public override void FeatureDeactivating(SPFeatureReceiverProperties properties)
        {
            SPWeb currentWeb = (SPWeb)properties.Feature.Parent;
            currentWeb.AllowUnsafeUpdates = true;
            string theme = currentWeb.Theme;
            string logoUrl = currentWeb.SiteLogoUrl;
            currentWeb.ApplyTheme("none");
            currentWeb.SiteLogoUrl = "/_layouts/images/titlegraphic.gif";
            currentWeb.Update();
            currentWeb.AllowUnsafeUpdates = false;
            currentWeb.Dispose();
        }

        public override void FeatureInstalled(SPFeatureReceiverProperties properties)
        {
            // Not being used
        }

        public override void FeatureUninstalling(SPFeatureReceiverProperties properties)
        {
            // Not being used
        }
    }
}

I’m also taking the opportunity to apply the client’s default logo for the site upon activation of the feature.
Step 4: Put your theme into the solution and make sure it deploys to the TEMPLATE/THEMES folder and place any images into the appropriate folders within TEMPLATE/IMAGES.
Step 5: Build the WSP and deploy to SharePoint for testing. You will need to activate the feature on the Web Application before creating any new sites. When you create new sites, the feature should automatically be activated to deploy the custom theme branding to all news sites on that web application. There is plenty of room for improvement, so comments are welcome!

11 December 2009

The Return of EndUserSharePoint.com

Earlier this week, EndUserSharePoint.com relaunched with a new hosting provider. Along with the relaunch of the website, a new look and feel has been applied and a lot of new features have been incorporated. Hurry over and check it out!

While you're at it, here are the articles that I've publised on EUSP.

02 December 2009

End User SharePoint Down!

I hate to see this for a good friend, but the most popular SharePoint site on the net has gone down. Jump over to http://www.endusersharepoint.com/ to encourage Mark Miller to keep plugging away at getting the site back online - I know he's working diligently to get it going again.

It does appear that he was able to retrieve all of his content (posts and comments), so at least nothing was lost.

Mark, here's wishing you the best in getting your site operational again. There's a big hole in the SharePoint community without the resources available on your site.

18 November 2009

jQuery Modal Display Optimization

I have been doing a lot of work with jQuery lately and decided that I would create my own modal popup display. However, I want to look for ways to optimize this code, if there are any. Anyone have any suggestions?

  1: jQuery.fn.showAlert = function(text, duration, opacity, inSpeed, outSpeed, width) {
  2:     var content = "<div id=\"alert\"><div id=\"boxes\"><div id=\"dialog\" class=\"window\">" + text + "<div id=\"close\">OK</div></div></div><div id=\"mask\" name=\"modal\"></div></div>";
  3:     $(this).append(content);
  4:     var mask = $("#mask");
  5:     mask.css({ 'position': 'absolute',
  6:         'z-index': 9000,
  7:         'background-color': '#000',
  8:         'top': '0px',
  9:         'left': '0px',
 10:         'opacity': 0
 11:     });
 12: 
 13:     var dialogContainer = $("#boxes");
 14:     dialogContainer.css({ 'width': width,
 15:         'height': '250px'
 16:     });
 17: 
 18:     var dialog = $("#dialog");
 19:     dialog.css({
 20:         'position': 'absolute',
 21:         'z-index': 9999,
 22:         'background-color': '#ffffff',
 23:         'top': '0px',
 24:         'left': '0px',
 25:         'padding': '5px',
 26:         'border': 'solid 2px black',
 27:         'width': width
 28:     });
 29:     dialog.hide();
 30: 
 31:     var maskHeight = $(document).height();
 32:     var maskWidth = $(document).width();
 33: 
 34:     var dialogTop = ($(window).height() - dialog.height()) / 2 + $(window).scrollTop() + "px";
 35:     var dialogLeft = ($(window).width() - dialog.width()) / 2 + $(window).scrollLeft() + "px";
 36: 
 37:     dialog.css({ 'top': dialogTop, 'left': dialogLeft });
 38: 
 39:     mask.css({ 'width': maskWidth, 'height': maskHeight });
 40:     mask.fadeTo(inSpeed, opacity);
 41: 
 42:     dialog.fadeIn(inSpeed);
 43: 
 44:     var close = $("#close");
 45:     if (duration < 0) {
 46:         close.css({ 'cursor': 'pointer' }).click(function() {
 47:             var newSpeed = outSpeed / 2;
 48:             dialog.fadeOut(newSpeed, function() {
 49:                 mask.fadeOut(newSpeed, function() {
 50:                     $("#alert").remove();
 51:                 });
 52:             });
 53:         });
 54:     }
 55:     else {
 56:         close.hide();
 57:         window.setTimeout(function() {
 58:             var newSpeed = outSpeed / 2;
 59:             dialog.fadeOut(newSpeed, function() {
 60:                 mask.fadeOut(newSpeed, function() {
 61:                     $("#alert").remove();
 62:                 });
 63:             });
 64:         }, duration);
 65:     }
 66: }
 67: