Stylish Gears: Customizing SPLongOperation

A frequently-asked branding question is how to customize the “gear” page shown during an SPLongOperation. The short answer is “you can’t”; but that’s not entirely true. The operation can be slightly customized using its LeadingHTML and TrailingHTML properties, which are written directly to the response stream. Because they aren’t encoded, we can use one to inject some JavaScript into the page that can manipulate the DOM, insert a stylesheet, really do anything we want. It’s not an ideal solution, as there will be a brief moment where the page is shown in its original form before the script can execute, but I believe it’s about the best we can do without directly modifying 12\TEMPLATE\LAYOUTS\gear.aspx. SharePoint's Gear of War

As a quick proof of concept, here’s the source of an .aspx you can place in LAYOUTS to see a long operation page that uses the current theme:

<%@ Page Language="C#" %>
<%@ Import Namespace="Microsoft.SharePoint" %>

<script language="C#" runat="server">
  protected override void OnLoad(EventArgs e)
  {
    string themeUrl = SPContext.GetContext(this.Context).Web.ThemeCssUrl;
    using (SPLongOperation op = new SPLongOperation(this.Page))
    {
      StringBuilder sb = new StringBuilder();
      sb.Append(themeUrl+"</span> \n");
      sb.Append("    <script language=\"javascript\"> \n");
      sb.Append("      (function(){ \n");
      sb.Append("        var objHead = document.getElementsByTagName('head')[0]; \n");
      sb.Append("        if(objHead) { \n");
      sb.Append("          var objTheme = objHead.appendChild(document.createElement('link')); \n");
      sb.Append("          objTheme.rel = 'stylesheet'; \n");
      sb.AppendFormat("          objTheme.href = '{0}'; \n", themeUrl);
      sb.Append("          objTheme.type = 'text/css'; \n");
      sb.Append("        } \n");
      sb.Append("      })();");
      sb.Append("\n<"+"/script><span>");
      op.TrailingHTML = sb.ToString();
      op.Begin();

      System.Threading.Thread.Sleep(10000);
    }
  }
</script>

I use a StringBuilder because embedded scripts don’t play well with multi-line constants. In production, I would probably embed the script as a resource.

Here’s the result with the built-in Granite theme:
Granite-Themed SPLongOperation