Saturday, November 15, 2008

Suppressing Core.js for Authenticated Sites

Requirement:
Do not download core.js to reduce page size/load time. ( sounds a common requirement in web across all technologies !) .

Solution:
Well, the starting point was http://msdn.microsoft.com/en-us/library/bb727371.aspx?ppud=4
Good technique to put core.js to rest and save 255kB ( which was 25% of my page size. Huge savings). Below article is extension further to the msdn article.

Tricky part is ours was a Intranet site - NTLM authenticated and the article demonstrated quick fix for anonymous users and no solution for Authenticated Users. So we needed a customized solution to sit top of the msdn solution.

Two distinct set of users were there in our site a) Authors, Admins etc b) Employees

The pages would have SiteActions enabled for former set based on their security permissions and not shown for rest of the users.

Our pages were highly customized and we were sure we werent using any Sharepoint controls, OOB Web parts which need core.js except SiteActions. (Couple, I found to use core.js - Site Actions, Welcome Control - you could see these in press releases site of Publishing template)

Now after narrowing down to SiteActions to be only control requiring core.js, the need was to download/suppress core.js based on this control. Some options considered

Option 1: In the msdn solution, see if you can add few static rules, like all users who needs to be shown SiteActions button would belong to this group.

protected override void OnInit(EventArgs e)
{
if (HttpContext.Current.Request.IsAuthenticated && User-belongs-to-group(xyz)

)
{
Microsoft.SharePoint.WebControls.ScriptLink.RegisterCore(this.Page, true); } base.OnInit(e); }

Option 2: A generic approach to check user's permission set and and take a call on loading/suppressing core.js. However you would need to reconstruct the exact permission logic as SiteActions user control users to determine its visibility. This is scalable approach imposing no restrictions on security groups to be used by admin/authoring community.

We started out with this only to find SiteActions UserControl is a simple wrapper around MenuTemplate control, which was few layers deep. Deep Diving for few hours followed by googling for few minutes didnt help much and hence this option was shelved.

Option 3: OK. you want to load core.js only for SiteActions, then why not see if SiteActions is loaded and if so, load the core.js also.

This looked to be the best bet and we scripted the following code to aceive this

protected override void OnInit(EventArgs e)

{base.OnInit(e);if (IsSiteActionsMenuVisible())

{ScriptLink.RegisterCore(this.Page, true);}

}

bool IsSiteActionsMenuVisible()
{
//check if SiteActionsMenu is visible
try
{
Control ctl = FindControlRecursive(this.Page, "SiteActionsMenuMain");
if (ctl != null) return ctl.Visible;
return false;
}
catch (Exception e)
{
System.Diagnostics.Debug.WriteLine(e);
return false;
}
}


static Control FindControlRecursive(Control Root, string Id)
{
if (Root.ID == Id)
return Root;
foreach (Control Ctl in Root.Controls)
{
System.Diagnostics.Debug.WriteLine(Ctl.ID + ":" + Ctl.ClientID);
Control FoundCtl = FindControlRecursive(Ctl, Id);
if (FoundCtl != null)
return FoundCtl;
}
return null;
}

and well it worked. Great to see the page reduce by 25%!!!

Additional Option - more of an after thought was to extend the SiteActions control and make it register core.js. I like this kind of design - a simple philosophy of You-need-it-You-register-core.js. When I experiment that would publish my findings in the blog.


(BTW I couldnt dig out any documentation on controls using core.js ( same as with init.js). Only methodology was for us to knock of core.js in page and see if anything is breaking up. Any pointers on the same?)

Note: Condition to check SiteActionsMenu can be extended to check for other controls ( e.g Welcome Control) also and suppress core.js.

No comments: