So, do you remember when Knight Rider "jumped the shark?" When they had that season where instead of having a fast car, they added all sorts of flares and fins and enhancements to the stock car? Yeah I know I'm dating myself, but bear with me here. All those enhancements are like Custom Actions in SharePoint.
Say what?
OK...follow me here...SharePoint's the Trans Am, Custom Actions are all the fins and such on the car...but much cooler!!
Ok, that was kinda a stretch, but the concept's the same. Custom Actions in SharePoint allow for customization of the UI with some additional enhancements. Those enhancements can be tied to a List, a Content Type, File Type or ProgID. These can be placed, well, pertty much all across the SharePoint UI. They can go in the Ribbon, pretty much whereever the Ribbon is, menus like the Site Actions menu, as well as the drop-down menu for items (technically called the EditControlBlock). They can be set up to go to a URL, fire off some javascript, or, call a class.
Now, rather than go through a long conversation on all the things you can do, I wanted to put out a specific example. What we're going to do is key up a Custom Action that allows the individual to specify a new welcome page for non-publishing sites. All folks know that in a publishing site you can set up what's considered the welcome (or opening) page, but for stuff like team sites and enterprise wikis that's not happening. This example will walk you through the creation of a Custom Action that allows you to pick a different page (Basic or Web Part) and designate that as the welcome page.
Now, onwards!
Ok, let's set up the project. Fire up Visual Studio 2010, create an Empty SharePoint project, and choose either Sandbox or Farm (this'll work in either). After that click on the project, right-click and select Add --> New Item...then select the Empty Element item, and then click <Add>. Now you should have all you need to get moving.
So, let's take a look at the following Custom Action. Below is one that's specific to a content type: the Basic Page (0x010109) content type.
1: <?xml version="1.0" encoding="utf-8"?>
2: <Elements xmlns="http://schemas.microsoft.com/sharepoint/">
3: <CustomAction
4: Id="ECBItemCustomization"
5: RegistrationType="ContentType"
6: RegistrationId="0x010109"
7: Location="EditControlBlock"
8: Sequence="106"
9: Title="Set as Welcome Page">
10: <UrlAction Url="javascript:
11: var context = null;
12: var listId = '{ListId}';
13: var itemId = {ItemId};
14: var web = null;
15: var currentList = null;
16: var currentItem = null;
17: var rootFolder = null;
18: var listTitle = null;
19: var itemFileLeafRef = null;
20: var newWelcomePage = null;
21:
22: getWebSiteData();
23:
24: function getWebSiteData()
25: {
26: context = new SP.ClientContext.get_current();
27: web = context.get_web();
28: currentList = web.get_lists().getById(listId);
29: currentItem = currentList.getItemById(itemId);
30: rootFolder = web.get_rootFolder();
31: context.load(web);
32: context.load(currentList, 'Title');
33: context.load(currentItem, 'FileLeafRef');
34: context.load(rootFolder);
35: context.executeQueryAsync(setNewWelcomePage, failedCall1);
36: }
37:
38: function setNewWelcomePage()
39: {
40: listTitle = currentList.get_title();
41: itemFileLeafRef = currentItem.get_item('FileLeafRef');
42: newWelcomePage = listTitle + '/' + itemFileLeafRef;
43: rootFolder.set_welcomePage(newWelcomePage);
44: rootFolder.update();
45: context.executeQueryAsync(displaySuccess, failedCall2);
46: }
47:
48: function failedCall1()
49: {
50: alert('error calliing from getWebSiteData');
51: }
52:
53: function displaySuccess()
54: {
55: alert('Site Welcome Page sucessfully updated to: ' + newWelcomePage);
56: }
57: function failedCall2()
58: {
59: alert('error calliing from setNewWelcomePage');
60: }
61:
62: "/>
63: </CustomAction>
64: </Elements>
So, line 3 starts it all off with the CustomAction element. This'll go inside an Elements node (we created this when we selected the Empty Element item above). Lines 4-9 set up this action for what we want it to do. Line 4 states the action's ID. Lines 5 and 6 are key here as these are what tie it to a specific content type. So, we set the RegistrationType to ContentType, and then set the RegistrationId to 0x010109 (a real quick tip, to find a content type's ID, add a new Content Type item type like you did above for the Empty Element one, pick the relevant type you want to base it on, and the ID will be commented out in the resultant XML for it). Now that we set up it's type, we need to say where it's actually going to show up. That's where line 7 comes in. The Location attribute states where this will go, and for us to have it show up in the dropdown menu of the item we set this to EditControlBlock. Line 8 sets up the ordering priority of the action via the Sequence attribute and line 9 is the text that's displayed in the area (via the Title attribute).
So, those lines above result in where this Custom Action will appear, and how it will look (see image below, of a document library whose content type is a Basic Page).
Now that we have the location and how it'll look, we need to give it something to do. This is where the UrlAction element comes into play. This element lets you point to a valid URL, or execute some javascript. Now, here's the cool part, and brings us to the second point of our article here. SharePoint 2010 now comes with the new Client Object Model and allows access to it through scripting, in this case the ECMAScript Class Library. Why's this important? Well, this will allow us access to this site's objects via the client scripting mechanism. While you could also do this via an assembly, I wanted to show off what you could potentially do with the client OM.
So, line 10 sets up the UrlAction and the Url attribute to call some javascript. Lines 11-20 initialize the variables to be used, but take note of lines 12 and 13. See the items in the squiggly brackets? These are called Url Tokens and give access to specific infromation behind them. In this example {ListId} returns the GUID of the list that the action's working on, and {ItemId} returns the integer of the item within the list. We'll use these to grab the relevant objects and information to continue our process.
Line 22 calls the function we're creating at line 24-36. Within this function are the key lines that set up access to the necessary objects. Line 26 starts it all off as that's how we get access to the current context we're in. From this, we can get the actual website that we're in (line 27). Once we've a web object, using the information from the previous tokens, we can get all sorts of stuff. So we use this to get the list, item and rootFolder objects. Now, we don't really have those objects yet, we have to load them into the current context. This has to be done in order to retrieve those properties. And after all that, we need to actually execute the pending client request to get all that information (line 35).
Now that we got all that information, we can act on it. The function called upon a successful execution from the previous call (line 35) will allow us to actually set our new welcome page up. We get the title of the list, the physical filename of the item that we're on, concatenate it and then set the welcome page via the rootFolder object. In order for the change to take we fire off the update() method of the rootFolder. Now, just like before, we need to execute the request to actually do that work. All this happens on lines 38-46.
Upon successful execution, you can now click the 'Home' link on your site, and see that it goes to the page that you executed this Custom Action on. Pretty neat, eh?
So, what did we find out here? Through the utilization of just some XML and javascript (ECMAScript), SharePoint 2010 allows you to do some pretty neat (and relevant) stuff, right?
Hopefully this example will help you out, and put you on the path to creating your own Custom Actions. Enjoy! - M
Bonus Track!
Just cause I like to try and wire things up right, the below Custom Action creates an item in the Site Actions menu that reverts the site's welcome page back to the default one (in this case the SitePages/Home.aspx). It is hard-coded, but this is just to show you the example of how it's done. Enjoy! - M
1: <?xml version="1.0" encoding="utf-8"?>
2: <Elements xmlns="http://schemas.microsoft.com/sharepoint/">
3: <CustomAction
4: Id="SiteActionsToolbar"
5: GroupId="SiteActions"
6: Location="Microsoft.SharePoint.StandardMenu"
7: Sequence="1000"
8: Title="Set Welcome Page to Default">
9: <UrlAction Url="javascript:
10: var context=null;
11: var web = null;
12: var rootFolder = null;
13: var defaultWelcomePage = 'SitePages/Home.aspx';
14: setDefaultWelcomePage();
15: function setDefaultWelcomePage()
16: {
17: context = new SP.ClientContext.get_current();
18: web = context.get_web();
19: rootFolder = web.get_rootFolder();
20: context.load(web);
21: context.load(rootFolder);
22: rootFolder.set_welcomePage(defaultWelcomePage);
23: rootFolder.update();
24: context.executeQueryAsync(successCall, failCall);
25: }
26:
27: function successCall()
28: {
29: alert('Welcome Page set back to default');
30: }
31:
32: function failCall()
33: {
34: alert('fail');
35: }"/>
36: </CustomAction>
37: </Elements>