Tuesday, February 25, 2014

SPFeatureReceiver.FeatureUninstalling ...or is it solution retraction?

copyright from: blogs.sharepointdam.com

I just realized there isn't that much documentation available on SharePoint's FeatureUninstalling method, so I thought I should share my experience with it.
 
FeatureUninstalling will only be called when the feature is uninstalled on the last web application. Therefore it is somewhat like a "Solution is being Retracted" event.
 
The properties.Feature property will be null, so you need to access your feature elements via the SPFarm object (SPContext doesn't work here either, as has been documented a lot on the web).
 
A solution retraction does NOT necessarily call a FeatureDeactivating for all deployed feature instances, so you might want to iterate through your WebApplications and Sites to clean up and deactivate any remaining features.

Tuesday, February 18, 2014

MANAGING PATH CONTEXT IN SHAREPOINT

copy right from: spchris.com
When working with SharePoint’s UI, it is often difficult to work out where in the URL structure you are.
You may for instance be working at the root of a site collection, but that itself may be several layers deep.
Take the following example.
You have a site collection for your company, but each team maintains its own site collection under the managed path (with wildcard inclusion) /teams.
Some of the team sites use a template that includes a master page that references an image gallery script. This gallery script has to load images out of a document library local to each team site.
The problem of course is determining the URL to the code and images, when they could be located at /teams/team-a/gallery images or /teams/team-b/gallery images
Of course in a server-side solution this is simple, SharePoint provides the handy shortcut of~sitecollection. This works both directly in master pages:
1
<SharePoint:ScriptLink runat="server" Name="~sitecollection/Style Library/js/galleryscript.js" Language="javascript"/>
Or using a custom action within a SharePoint solution, sandboxed or otherwise:
1
2
3
4
5
6
7
xml version="1.0" encoding="utf-8"?>
    <CustomAction
        ScriptSrc="~sitecollection/Style Library/js/galleryscript.js"
        Location="ScriptLink"
    />
</Elements>
But how do we achieve the same within the front end itself?

Introducing _spPageContextInfo

The _spPageContextInfo object is a really wonderful little thing. It is added by theSPWebPartManager control, which is included in all of the out of the box master pages (including default.master and system.master) and I really strongly recommend is added to any custom master pages you create.
Because of it’s essentially omnipresent nature it makes using _spPageContextInfo a really simple matter of, well, using it.
It is a small object, containing only a few properties of the page, the site and the site collection it is part of. Here is a JSON representation of what it contains.
1
2
3
4
5
6
7
8
9
10
11
12
{
    alertsEnabled: true,
    allowSilverlightPrompt: "True",
    currentLanguage: 1033,
    pageItemId: 1,
    pageListId: "{6300d68a-4512-49f0-85b9-d3671855e31c}",
    siteServerRelativeUrl: "/teams/team-a",
    userId: 1,
    webLanguage: 1033,
    webServerRelativeUrl: "/teams/team-a/subsite",
    webUIVersion: 4
}
Here’s a brief explanation of the properties in it.

alertsEnabled

This one is simple, is SharePoint’s alerts email notification service enabled for the current web application. This maps to the SPWebApplication.AlertsEnabled property.

allowSilverlightPrompt

Will the user be prompted to download Silverlight if they do not already have it when they attempt to use Silverlight based UI elements. This maps to the SPWebApplication.AllowSilverlightPromptproperty.

currentLanguage

This is the current locale being used by the user, if they have not changed it to a custom one, then this maps to the SPWeb.Language property.

pageItemId

This is the ID of the current page’s item within the document library containing it.

pageListId

This is the GUID of the document library containing the current page.

siteServerRelativeUrl

This is the path of the site collection, relative to the web application.

userId

This is the user’s ID for the current site collection.

webLanguage

This is the default language for the current web. This maps to the SPWeb.Language property.

webServerRelativeUrl

This is the path of the web, relative to the web application.

webUIVersion

This is the UI version of the current web, determining if the master page and components in use and available is compatible with SharePoint 2007 (3), SharePoint 2010 (4) or SharePoint 2013 (5)
Note: The actual properties available varies depending upon where you happen to be. For instance the pageItemId and pageListId properties do not exist within system pages, as they do not have IDs and do not live within document libraries.

That’s pretty cool, but how do we use it?

Well, as they are properties we can pretty much use them however we wish. Let’s take a look at a simple way of referencing files in our gallery images document library, for example referencing a logo to use on the homepage.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
(function() {
 
    // The path to the image.
    var imagePath = '/gallery%20images/logo.jpg';
 
    // The relative URL is usually without the trailing /
    // however if we are on the root site collection then it
    // is simply / on its own and must be handled.
    if (_spPageContextInfo.siteServerRelativeUrl == '/') {
        imagePath = imagePath.substring(1);
    }
 
    // Build our full image path.
    imagePath = _spPageContextInfo.siteServerRelativeUrl + imagePath;
 
    // Finally set our image's source to the images path
    $('img#logoImage').attr('src', imagePath);
 
})();
Of course this is a rather contrived example, and you should probably be using the client side object model (CSOM) to pull items from a document library. However I hope it demonstrates how the object can be used.
A common use I use this for is is actually with the CSOM.
1
var ctx = new SP.ClientContext(_spPageContextInfo.webServerRelativeUrl);
I do it this way because I have had issues with concurrency when using the get_Current() method in SP.ClientContext when there is other code in use on pages that I do not have control over.