21 September 2011

SharePoint: Programmatically add JS/CSS to pages

John Chapman has a great article on creating a feature for your SharePoint installation that adds JavaScript and CSS files to all pages without touching the site's master page. The good folks on SharePoint.StackExchange.com helped me implement it and also modify the code to better utilize SharePoint's native control libraries.

First, follow the code provided by John Chapman. Then modify the CustomPageHead.ascx.cs to take advantage of the built-in SharePoint controls:
using System;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using Microsoft.SharePoint;
using Microsoft.SharePoint.WebControls;

namespace CustomPageHead.CONTROLTEMPLATES.CustomPageHead
{
public partial class CustomPageHead : UserControl
{
protected override void CreateChildControls()
{
base.CreateChildControls();

this.Controls.Add(new ScriptLink()
{
Name = "/_layouts/CustomPageHead/jquery-1.6.2.min.js",
Language = "javascript",
Localizable = false
});

this.Controls.AddAt(0,new ScriptLink()
{
Name = "/_layouts/CustomPageHead/some-custom-code.js",
Language = "javascript",
Localizable = false
});

this.Controls.AddAt(1,new CssRegistration()
{
Name = "/_layouts/CustomPageHead/some-stylesheet.css"
});
}
}
}
Note that using the native controls, you don't have to worry about paths to where the files will be; SharePoint will place these items in the following location on your server:
C:\Program Files\Common Files\Microsoft Shared\Web Server Extensions\14\TEMPLATE\LAYOUTS\CustomPageHead
Also, the advantage of using the this.Controls.AddAt() method is that you can specify where in the object hierarchy to add the specified object.

In addition, the solution can be generated into a *.WSP by selecting "Package" from Visual Studio's Build menu. The file can then be copied from the bin/Release folder and run on the command line to install the feature.

Special thanks goes to omlin and James Love for their help.

14 September 2011

SharePoint tabs UI for web parts

Christophe Humbert's beautiful Easy Tabs for SharePoint works wonderfully well; it automatically generates tabs for the web parts on the page. You simply drop the code Christophe provides into a content editor web part (CEWP) and off you go.

In a current project, we needed the ability to have all pages show tabs without dropping a CEWP on every page. The code needed to be on a page layout for a publishing site. The challenge? Christophe's code traverses up the DOM from the current CEWP to find the parent container of the web parts; unless you use a CEWP, it won't work.

Some serious trial-and-error, as well as posting to the SharePoint group on StackExchange.com, provided the clues; we need to provide a direct reference to the parent container of the web parts. Here's the part of the code that was moving up the DOM tree:
var el=document.getElementsByTagName("SCRIPT"),p=el[el.length-1],sT,a,sep,tabRow;
do {p=p.parentNode;sT=p.innerHTML.split("MSOZoneCell_WebPart");}while (sT.length<4 && p.parentNode.id!="MSO_ContentTable")
In the page layout, the web parts are in a Page Content control (PublishingWebControls:richhtmlfield), so here's the change to the JavaScript to reference that parent container:
var p,a,sep,tabRow;
p = document.getElementById('ctl00_PlaceHolderMain_ctl01__ControlWrapper_RichHtmlField');
Note that there's no need for the el variable or the do-while loop. You probably need to do some trial-and-error, using alert() statements to view the p.innerHtml and/or p.parentNode.innerHtml; this helped me discover what p was pointing to after the do-while and simply reference it directly.

07 September 2011

SharePoint: If your stylesheet isn't added to the page...

For a current project, I'm using a custom page layout within a publishing site. I had the following code in the my_page_layout.aspx file:
<asp:Content ContentPlaceholderID="PlaceHolderAdditionalPageHead" runat="server">
<link type="text/css" href="../../SiteAssets/js/jquery/jquery-ui-1.8.16/css/cupertino/jquery-ui-1.8.16.custom.css"/>
....
</asp:Content>
No matter what I did, the stylesheet wouldn't be available to the SharePoint page. However, another stylesheet was showing up. The difference? I was missing the rel="stylesheet" attribute on the bad link tag. Added it and everything worked.