Client Side Encryption of List Item Fields for SharePoint 2013 (Demo Project)

Some days ago I found this JavaScript library for client side encryption using standard crypto algorithms. Everything done in the browser. Cool!

 

Stanford Javascript Crypto Library: http://crypto.stanford.edu/sjcl/ – They say: “It uses the industry-standard AES algorithm at 128, 192 or 256 bits; the SHA256 hash function; the HMAC authentication code; the PBKDF2 password strengthener; and the CCM and OCB authenticated-encryption modes.”

 

Based on this I wanted to create a client side SharePoint List Item crypt module to encrypt (text) data in the users browser. So the data is stored in SharePoint encrypted. No one can read it without having the password.

Here is the code:

http://splistitemcrypt.codeplex.com/

It’s a coding exercise, nothing more!!!! Read the limitations below and be sure: there are more limitations I do not know at the moment…

 

My solution is very simple: I created a Visual Web Part with Visual Studio 2012. This web part contains everything I need for encryption / decrpytion.

1. It contains the Standford Javascript Crypto Library.

2. It contains a copy of jQuery 1.10.1.

3. It contains a Base64 serialized image that is used to mark input fields as “encryption protected”.

4. Some custom javascript.

That’s it. Small footprint. – The web part needs to be placed on each list form (new / edit / display) and on each list view page. Everything else is done by the Web Part.

 

Benefits:

  • Client side data encryption.
  • Industry standard encryption. Theoretically possible to decrypt the data later outside of SharePoint using the correct password and some tools / libraries.
  • You can share the password with anyone who needs to decrypt the data. It’s not bound to your user account.

 

Limitations – be careful to read and understand them before using it in any way. – There are more limitations. The list is not complete!!!

  • First of all: It’s a single-person’n’quick-done demo project. Nothing for production use. – You could use your data! – I’m responsible for any problems.
  • Works only for text fields and multi line text fields without HTML formatting.
  • (Single line) text fields in SharePoint are limited to 255 characters length. The encrypted data is stored as Base64 in the field. So it’s not possible to encrypt 255 characters to the same amount of data: 255 bytes of plain text chars are much more that 255 bytes in encrypted state. SharePoint and my module does not handle this situation. (Because it’s a demo project not a product 😉 )
  • If you loose the password there is no way (other than “brute force”) to get your data back. There is no back door.
  • The data cannot be searched. – You should exclude the list from being crawled.
  • No way to change the password. – If this will be possible in the future than there will be no way to migrate already encrypted data. This is because it’s client side encryption. The server does never now the password. So it cannot migrate the data from the current version of the project to a new version.
  • No inline edit on list view pages!
  • No “decrypt” option to permanently remove encryption.

At all: The project is not perfect, in any way.

 

Here is a step-by-step guide of how to use it:

1. Create a site collection.

2. Add a custom list called “Crypted Data”.

3. Add a new multi line text column as “plain text”

image

4. Click “New item”. This is the default “New” form.

 image

5. To add the crypto web part choose “Edit Page” from the site actions menu. Click “Add a Web Part”. Select category “Custom”, select web part “ikarstein’s List Item Crypt” and zone “Main”. Then click button “Add”.

image

 

6. Now you get a form section on the form asking for your password, because the password cache of your browser is empty.

SNAGHTML2b6e0a

7. After you enter the password and click the button “Set Password” you see lock icons behind the two text fields. These are added dynamically by the crypto web part.

image

8. Now you can add data as normal to the list item:

SNAGHTML2dcf6a

9. On saving the list item you will see the encrypted content for a short time. Before the encrypted and Base64 encoded data you see a prefix @@*[ – This I use to identify encrypted values.

image

10. After saving and back on the list view page you see this:

image

After adding the web part to the list view page you see this (automatically):

image

the values are decrypted using the browser cached password.

11. The same for edit form and display form. If you do not add the web part you will see the encrypted values. Like here:

image

After editing the form page you see the decrypted values:

image

The same for edit…

image

After you edit the web part you can edit the decrypted values and change them:

image

Some changes and saving it. This is the list view afterwards:

image

12. The inline edit mode does not work!!!

SNAGHTML3b7b99

 

It’s very simple. Look at the code on CodePlex. Just one note: The web party loads its own jQuery version only if the page does not contain jQuery already.

New Demo Project Released: SharePoint Web Change Log – An Alternate Notification Feature

I created an alternated notification feature for SharePoint 2010. It’s a demo project for SharePoint 2010. I’ve done it for some practice in SharePoint development and just for fun 🙂

It’s intended to replace the default notification feature of SharePoint 2010 where you can subscribe to notifications list based. – With my feature a user can subscribe to all changes of a SharePoint Web by using a menu entry in the Personal Actions menu.

The notification mail is send to any subscribing user once a day. (Please notice that at the moment there is no security trimming for the notification mail!)

Project site: http://spwebchangelog.codeplex.com

 

How it works:

1. There is a web scoped feature and a farm scoped feature.

2. The web scoped feature is responsible for the Personal Actions menu entry and the change log at web scope.

image

3. The farm scoped feature deploys a timer job that scans each web every day and sends the notification mail if there are any changes in the web.

image

4. The job can be scheduled as you like.

5. On each web where the web scoped feature is active, there are two hidden lists:

image

This list contains an list item for each user that has subscribed for notifications. If a users unsubscribes the list item is removed.

image

6. If the web feature is active the “Change Log” list will contain a list item for each change in other lists of the web.

A list event receiver recognizes each list level change: Created lists, deleted lists.  It adds list item event receivers to each list in the web.

A list item event receiver creates items in the “Change Log” list for each list item action: add, update, delete.

7. If the web scoped feature is deactivated the list event receiver and all list item event receivers are removed. If the feature gets activated the list event receiver and a list item event receiver for each existing list are registered.

8. The farm scoped feature deploys a timer job that scans each web of a specific web application. If the web feature is active in a web the timer job looks for the change log list and for subscribers. If there are at least one subscriber and at least one one change since the last job run the notification mail is send.

image

9. It’s localized for german and english. The notification mail text is part of a resource file. But the resource file value for the mail text can be replaced by using a Web Property.

image

10. The notification mail is not security trimmed! That’s important for use in a production environment!

11. It’s tested in both a german and an english SharePoint system with both language packs, with multiple site collections and multiple webs and sub webs. I’d like to hear your experiences. Please report any bug. Feel free to modify it but please send me your improvements!

“SPWebPSConsole”: Web based PowerShell Console for SharePoint (A new project on Codeplex)

This project is a stand-alone clone of my project „Web based PowerShell Console” released on 2011-09-02 on Codeplex and in this blog article:

https://blog.kenaro.com/2011/09/02/webpsconsole-web-based-powershell-console-a-new-project-on-codeplex/

I’ve adapted the project to run in the SharePoint 2010 Central Administration.

The project is on Codeplex: http://spwebpsconsole.codeplex.com

To install the project just by deploying the solution. The SharePoint feature will automatically be activated in the Central Administration Web Application without need of further actions.

In the “System Settings” section of the CA you’ll find a new link:

image

Just click it and you will get this:

image

image

The SharePoint PowerShell SnapIn is loaded automatically so that you can start immediately to execute SharePoint Cmdlets!

Here is an example:

“Get-SPSite”

image

Or this one:

image

Request for value for missing parameter “Path” of Cmdlet “Backup-SPSite”

image

Final output:

image

The project is “BETA”. I need your help to improve the project. Please feel free to test it or to extend it. But if you do so please send me your results!

Have fun!

“WebPSConsole”: Web based PowerShell Console (A new project on Codeplex)

Starting at 12th of September 2011 I’ll be freelancer. – In August I had some vacation days to spend. – So I created a new project for me – and for you.

I call it “Web based PowerShell Console” or “WebPSConsole”.

It is a full featured Browser based PowerShell console that enables you to work on a server machine remotely. It’s like PowerShell remoting but it’s not the same. While PowerShell remoting uses “WinRM” the tool that I’ve created uses a “normal” PowerShell host that will be executed in an IIS environment. (Please see my comment related to “PowerGUI Pro Mobile Shell” at the end of this article.)

That means: With my tool you will have a ASP.NET 4.0 based Web Application that can be accessed by a browser. The ASP.NET web app has a .ASPX site and some code behind. On the server in the ASP.NET context a PowerShell Host developed by me is running that accepts commands send by the clients Browser. If a command is send it will be executed by the PowerShell Host. All output is send back to the clients Browser.

It’s on Codeplex: http://webpsconsole.codeplex.com with all source code! – It’s ALPHA. I’ve done lots of testing but I’m a single developer with a single machine… I’d be happy to get your improvements or experiences!

Lets have a look at the app:

image

That is the “GUI”. The black frame will contain the output of the server side PowerShell session.

Let’s enter a command.

get-childitem c:windows | select -first 5

image 

After clicking “Send” the command is send to the server. The server executes the command and returns the PowerShell output.

Let’s try this:

get-credential

image 

You see the blue colored input box for the credential information input.

Here you see the implemented “session timeout”:

image

After 15 minutes of inactivity you’ll get a warning. After 20 minutes the session will be terminated. After termination you are not able to access the old session including session history!

Let’s try this:

a$ = read-host

image 

Here you get an input field for a single line of text. The output is stored in variable $a. Let’s check the content of variable $a after sending the input:

image 

Now let’s test the functionality of completing missing cmdlet parameters:

get-content

image 

image

Leave the last line empty and click “Send”.

image

You get:

image

Now let’s test the “choice” functionality:

image 

After “Send” you get:

image 

You see here the blue colored choice input field. If you choose “Halt Command” in this case the “Hello Ingo” command will not be executed:

image 

If you select “Cancel” in such cases the complete PowerShell pipeline will be stopped! Not only the current command!

You can set colors a you need to:

image 

Than “Send” and test it with:

image 

You’ll get:

image

Now let’s have a look at the function “Download console as RTF”. You’ll find the link above the console frame.

image 

Click “Open”.

image 

This is a Rich Text Format copy of the complete console output! – A “Clear-Host” will not clear this output! – This file can only be downloaded while the current session running. After the session ends you will not be able to access the information anymore!

Let’s try “Show current buffer”. This command is above the console frame too.

image 

Here you get the “real” PowerShell buffer as HTML. This page can be save.

Let’s try:

clear-host

image 

Open “Show current buffer” again:

image 

(It’s empty now because clear-host did clear the PowerShell buffer!)

A word to the keyboard usability:

In the command input field you can use ESCAPE to clear the input field.

You can use CTRL+ENTER to send the command.

In other input fields (choice, credential, read-line,…) except “Read-Key” (see below) you can use ESCAPE to cancel the current operation and pipeline.

You can use there ENTER to send your entered data.

You can use TAB and SHIFT+TAB to navigate inside the input frame: input field, Send button and Cancel button.

The “Trace log” is an optional frame that maybe shows more information about your server connection and the “work behind”. Just click the line and the frame will be shown:

image 

(“Send buffer as HTML” is caused by the “Show current buffer” function.)

You can close the PowerShell session by clicking the “x” in the dialog title (beside “v0.1.0.0”):

image 

Now you can close the Browser or click “Ok” to start a new session. Or reload the Browser page to create a new session.


Setup

Now I want to tell you how to install the project.

First of all you need IIS. This can be installed on Windows 7 too.

You need a user account for executing PowerShell at server side. This account is used by every user of WebPSConsole: Each user of WebPSConsole will be impersonated at the server with the “execution account”. Here you should choose the account very carefully.

1.

Create a directory on the server where you store the binaries. You create a folder “c:inetputwebpsconsole”.

image 

 

2.

Copy the binaries there.

image 

 

3.

Open IIS Manager.

Create a new Application Pool for the “execution account”. This account need to execute ASP.NET 4.0 code.

image 

Select “Classical Mode” for the application pool! – Please check the settings. In my case the settings were not used. After creating the app pool I had to edit it and set “Pipeline Mode” and “Framework Version” again!!!

 

4.

Create a new web application “WebPSConsole” using the previously created application pool.

Right click the “Sites” node in IIS Manager.

image 

You get this dialog. Fill in your specific informations. Here is my sample. I’ll use “ikWebPSConsole” as host header name in this setup demo because the host header “webpsconsole” already exists for development purpose.

image 

Click the “Select” button beside “Application pool:

image 

“OK”.

My sample data:

image 

(In order to get this working on my machine I have to edit c:windowssystem32driveretchosts and insert “ikWebPSConsole” as new local DNS entry.)

 

5.

Change the Authentication settings. Disable “Anonymous Access” and enable “Windows Authentication”.

Select the web app in the treeview. On the right side double click “Authentication”.

image 

You get:

image 

First double click “Anonymous Authentication” and deactivate it!

image 

Now enable “Windows Authentication” the same way!

 

6.

You should restrict the usage of the web app by setting access restrictions.

image 

There you can grant or deny access to the web app for specific users, e.g. administrators.

As an example: Here only “DOMAINAdministrator” will have access to WebPSConsole.

image 

You should enable SSL.

I’ve done this already in the setup example above while creating the web app.

You could use “SSL client certificates” to protect the web app.

7. Test the app.

Security

  • I’ts as secure as you configure it!
  • You can restrict the rights of the console on the server by selecting a carefully configured user account as application pool account. You don’t have to configure this user to be “local admin” 😉
  • You can use SSL! (As shown above)
  • You can use Client-SSL-Certificates!
  • You can restrict client IP addresses!
  • You can restrict access by secifying users (as shown above).
  • BUT be sure you know what you do – as always 😉

Limitations

  • It’s not as fast as a local PowerShell because of the client-server-interaction.
  • Currently it runs only under the user context of the application pool. There should be “real” impersonation of the logged in user. But this did not work.
  • It consumes memory on the server because of the data saved on the server in the session. Be sure to monitor the servers memory usage if you deploy it on live servers!
  • There is not “Progress” support at the moment!

 

Ideas for future features:

  • Command completion (like “Intellisence”)
  • Client side syntax check
  • “Color code”

Please help me to impove the app! – Please post comment of your experiences!


Have fun!


For this project I’ve used:

 

 

A word to PowerGUI Pro MobileShell

As I said I’ve developed this project in my last vacation. After finishing v0.1.0.0 I’ve seen PowerGUI Pro MobileShell by Quest Software
. It’s based on the same idea as my project but is older and has more features I think. I only know a YouTube video of it because I do not know the commercial version of PowerGUI. – Beside this the free PowerGUI tool is my favorite PowerShell IDE. – For use on a live server you should think about using PowerGUI Pro MobileShell!

Walkthrough: Creating a simple Sequential Workflow with a custom Task Form in SharePoint 2010 using Visual Studio 2010 (Part 3 of (2+1))

 

This article belongs to these previous posts:

You should read this article if you have problems to deploy my sample project on Codeplex (http://spworkflowdemo.codeplex.com/) in Visual Studio 2010.

1. Download the code and copy them into your sources folder.

2. Create a site collection in SharePoint 2010, e.g. “http://sharepoint.local/sites/workflow”. Use “Blank Site” site template.

3. Open the solution file in Visual Studio 2010 (file with extension “.sln”).

4. In the Solution Explorer pane select the project node.

5. Set the “Site URL” property to your previously created SharePoint Site (see step 2 above).

image

6. In the Solution Explorer pane select the “Workflow 1” node in the project.

7. In the Properties pane modify the value of “Display Name”. Set it to “Workflow 1”.

8. Now click into the values edit box of “History List” (or “Target List” or “Task List”). This will open a wizard.

9. In the wizard specify the values of the Workflow Association. Choose the values shown in following screenshot:

Step “A”:

image

Click “Next”.

Step “B”:

image

Click “Next”.

Step “C”:

image

Click “Finish”.

10. Now you should be able to deploy the project.

Walkthrough: Creating a simple Sequential Workflow with a custom Task Form in SharePoint 2010 using Visual Studio 2010 (Part 1 of 2)

In this walkthrough I want to show you how to create a Sequential Workflow with Visual Studio 2010 for use in SharePoint 2010. – I will show how to create a custom Task Form for interaction with users. The Task form will be a native SharePoint list form. No InfoPath. There are many InfoPath samples out there but they cannot be used on a SharePoint Foundation 2010 platform. But workflows can be used on SharePoint Foundation 2010 too!

To reproduce the following steps you need to create a SharePoint site. – In the walkthrough I’ll use a Site Collection located at “http://sharepoint.local/sites/workflow”.

This blog post is part 1 of 2. It describes the steps 1 to 15. Read part 2 here: https://blog.kenaro.com/2011/03/30/walkthrough-creating-a-simple-sequential-workflow-with-a-custom-task-form-in-sharepoint-2010-using-visual-studio-2010-part-2-of-2/

You can download – and help to develop – the whole demo project source code at Codeplex: http://spworkflowdemo.codeplex.com/

(If you need assistance for the deployment process because of deployment errors please see this third post of this series: https://blog.kenaro.com/2011/04/22/walkthrough-creating-a-simple-sequential-workflow-with-a-custom-task-form-in-sharepoint-2010-using-visual-studio-2010-part-3-of-21/)

Let’s start…

1. We create the Site Collection. Use the “Blank Site” site template.

image

2. In Visual Studio 2010 we create a Empty SharePoint Project. I named it “ik.SharePoint2010.Workflow”

image

We create it with “Deploy as farm solution” and specify the location “http://sharepoint.local/sites/workflow/”.

image

3. This is the project structure at start:

image

4. First we need to create an instance of the Workflow History list that is needed for the workflow.

Create a new “Empty Element” project item named “Workflow History”.

image

Open the created “element.xml” file and modify it as shown below.

1: <?xml version="1.0" encoding="utf-8"?>
2: <Elements xmlns="http://schemas.microsoft.com/sharepoint/">
3:  <ListInstance Title="Workflow History"
4:  OnQuickLaunch="TRUE"
5:  TemplateType="140"
6:  FeatureId="00BFEA71-4EA5-48D4-A4AD-305CF7030140"
7:  Url="Lists/WorkflowHistory"
8:  Description="">
9:  </ListInstance>
10: </Elements>

The “TemplateType” attribute represents the “Workflow History” list template. It resists on a SharePoint feature with ID “00BFEA71-4EA5-48D4-A4AD-305CF7030140”. It’s a native SharePoint feature.

You can add the attibute “Hidden” to the “ListInstance” tag and set it’s value to “TRUE” to hide the list as it’s done by SharePoint by default for this list. In this case you should also change “OnQuickLaunch” to “FALSE”. For my demo purpose I want to have “Workflow History” visible and on the Quick Launch bar.

5. Now we will create all tools we need for a “Workflow 1”. (May be I’ll create more workflow demos later. So it’s number 1.)

6. We create the SharePoint fields for “Workflow 1”. Therefore we create another “Empty Element” project item named “Workflow 1 Fields”.

image

I’ll create 3 fields for use in the Task Form we will create: Test1, Test2, Test3. They are all fields of type Text.

1: <?xml version="1.0" encoding="utf-8"?>
2: <Elements xmlns="http://schemas.microsoft.com/sharepoint/">
3:  <!-- Fields for Task 1 of Workflow 1-->
4:  <Field ID="{2FE15855-3CAB-44A6-AB29-1600204FCA20}" Name="Workflow1Task1_Test1"
5:  MaxLength="255" DisplayName="Test1" Description=""
6:  Direction="None" Type="Text" Overwrite="TRUE"
7:  xmlns="http://schemas.microsoft.com/sharepoint/" />
8:  <Field ID="{517B22A5-1B89-4C24-82BE-3D4FD99645BC}" Name="Workflow1Task1_Test2"
9:  MaxLength="255" DisplayName="Test2" Description=""
10:  Direction="None" Type="Text" Overwrite="TRUE"
11:  xmlns="http://schemas.microsoft.com/sharepoint/" />
12:  <Field ID="{3ECFF1FE-F56B-4556-8805-4570D9422FF4}" Name="Workflow1Task1_Test3"
13:  MaxLength="255" DisplayName="Test3" Description=""
14:  Direction="None" Type="Text" Overwrite="TRUE"
15:  xmlns="http://schemas.microsoft.com/sharepoint/" />
16: </Elements>

7. Now we create a new “Module” project item named “Workflow 1 Forms”. In this module we will store the Task Form.

image

Remove the “Sample.txt” file from the created module.

Create a new “Application Page” project item named “Task1Form.aspx”.

image

This project item will stored in the folder “Layoutsik.SharePoint2010.Workflow”.

image

Move the project item “Task1Form.aspx” using Drag & Drop into the module “Workflow 1 Forms”.

image

Remove the “Layouts” folder from the project. It should be empty.

8. We open “Task1Form.aspx”

First we need to edit the “Page” tag of the ASPX site.

1:  <%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Task1Form.aspx.cs" Inherits="ik.SharePoint2010.Workflow.Task1Form" MasterPageFile="~masterurl/default.master"  %>

Now we insert the following code into the “PlaceHolderMain” content placeholder.

1:     <asp:ScriptManagerProxy runat="server" ID="ProxyScriptManager">
2:     </asp:ScriptManagerProxy>
3:     <table width="100%" border="0" cellpadding="0" cellspacing="0">
4:         <tr>
5:             <td valign="top">
6:                 <table cellspacing="0" cellpadding="4" border="0" width="100%">
7:                     <tr>
8:                         <td class="ms-vb">
9:                             &nbsp;
10:                         </td>
11:                     </tr>
12:                 </table>
13:                 <table border="0" width="100%">
14:                     <tr>
15:                         <td>
16:                             <table border="0" cellspacing="0" width="100%">
17:                                 <tr>
18:                                     <td class="ms-formlabel" valign="top" nowrap="true" width="25%">
19:                                         <b>Title:</b>
20:                                     </td>
21:                                     <td class="ms-formbody" valign="top" width="75%">
22:                                         <SharePoint:FormField runat="server" ID="ff4" ControlMode="Display" FieldName="Title" /><br />
23:                                     </td>
24:                                 </tr>
25:                                 <tr>
26:                                     <td width="25%" class="ms-formlabel">
27:                                         <b>Test1:</b>
28:                                     </td>
29:                                     <td width="75%" class="ms-formbody">
30:                                         <SharePoint:FormField runat="server" ID="ff1" ControlMode="Edit" FieldName="Workflow1Task1_Test1" />
31:                                         <SharePoint:FieldDescription runat="server" ID="ff1description" FieldName="Workflow1Task1_Test1"
32:                                             ControlMode="Edit" />
33:                                     </td>
34:                                 </tr>
35:                                 <tr>
36:                                     <td width="25%" class="ms-formlabel">
37:                                         <b>Test2:</b>
38:                                     </td>
39:                                     <td width="75%" class="ms-formbody">
40:                                         <SharePoint:FormField runat="server" ID="ff2" ControlMode="Edit" FieldName="Workflow1Task1_Test2" />
41:                                         <SharePoint:FieldDescription runat="server" ID="ff2description" FieldName="Workflow1Task1_Test2"
42:                                             ControlMode="Edit" />
43:                                     </td>
44:                                 </tr>
45:                                 <tr>
46:                                     <td width="25%" class="ms-formlabel">
47:                                         <b>Test3:</b>
48:                                     </td>
49:                                     <td width="75%" class="ms-formbody">
50:                                         <SharePoint:FormField runat="server" ID="ff3" ControlMode="Edit" FieldName="Workflow1Task1_Test3" />
51:                                         <SharePoint:FieldDescription runat="server" ID="ff3description" FieldName="Workflow1Task1_Test3"
52:                                             ControlMode="Edit" />
53:                                     </td>
54:                                 </tr>
55:                             </table>
56:                         </td>
57:                     </tr>
58:                 </table>
59:                 <table cellspacing="0" cellpadding="4" border="0" width="100%">
60:                     <tr>
61:                         <td nowrap="nowrap" class="ms-vb">
62:                             <asp:Button Text="Save As Draft" runat="server" ID="btnSaveAsDraft" />
63:                         </td>
64:                         <td>
65:                             <asp:Button Text="Complete Task" runat="server" ID="btnComplete" />
66:                         </td>
67:                         <td nowrap="nowrap" class="ms-vb" width="99%">
68:                             <asp:Button Text="Cancel" runat="server" ID="btnCancel" />
69:                         </td>
70:                     </tr>
71:                 </table>
72:             </td>
73:             <td width="1%" class="ms-vb" valign="top">&nbsp;</td>
74:         </tr>
75:     </table>
76:

Now we add some ASP.NET code into the “PlaceHolderPageTitle” content placeholder.

1:     <SharePoint:ListFormPageTitle runat="server" />

Furthermore we add this lines of code into the “PlaceHolderPageTitleInTitleArea” content placeholder.

1:     <span class="die">
2:         <SharePoint:ListProperty Property="LinkTitle" runat="server" ID="ID_LinkTitle" />
3:         : </span>
4:     <SharePoint:ListItemProperty ID="ID_ItemProperty" MaxLength="40" runat="server" />

At least we add the following code into the “PlaceHolderAdditionalPageHead” content placeholder.

1:     <SharePoint:UIVersionedContent UIVersion="4" runat="server">
2:         <contenttemplate>
3:             <SharePoint:CssRegistration Name="forms.css" runat="server"/>
4:         </contenttemplate>
5:     </SharePoint:UIVersionedContent>

You can see the input fields for the three fields of Task 1. Furthermore you see three buttons. For them we now create some “code behind”.

1: using System;
2: using Microsoft.SharePoint;
3: using Microsoft.SharePoint.WebControls;
4: using Microsoft.SharePoint.Utilities; 
5:
6: namespace ik.SharePoint2010.Workflow
7: {
8:     public partial class Task1Form : WebPartPage
9:     {
10:         protected void Page_Load(object sender, EventArgs e)
11:         {
12:             btnSaveAsDraft.Click += new EventHandler (btnSaveAsDraft_Click);
13:             btnComplete.Click += new EventHandler (btnComplete_Click);
14:             btnCancel.Click += new EventHandler (btnCancel_Click);
15:         }
16:
17:         void btnCancel_Click(object sender, EventArgs e)
18:         {
19:             CloseForm();
20:         }
21:
22:         private void CloseForm()
23:         {
24:             if ( ( SPContext.Current != null ) && SPContext.Current.IsPopUI )
25:             {
26:                 this.Context.Response.Write("<script>window.frameElement.commitPopup();</script>" );
27:                 this.Context.Response.Flush();
28:                 this.Context.Response.End();
29:             }
30:             else
31:             {
32:                 string str = this.Page.Request.QueryString["Source"];
33:                 if ( ( str != null ) && ( str.Length > 0 ) )
34:                 {
35:                     SPUtility.Redirect(string.Empty, SPRedirectFlags.UseSource, this.Context);
36:                 }
37:             }
38:         }
39:
40:         void btnComplete_Click(object sender, EventArgs e)
41:         {
42:             SPList l = SPContext.Current.List;
43:             SPListItem li = SPContext.Current.ListItem;
44:             li[SPBuiltInFieldId.TaskStatus] = "Tasks_Completed";
45:             li[SPBuiltInFieldId.PercentComplete] = 1;
46:
47:             SaveButton.SaveItem(SPContext.Current, false, "" );
48:
49:             CloseForm();
50:         }
51:
52:         void btnSaveAsDraft_Click(object sender, EventArgs e)
53:         {
54:             SaveButton.SaveItem(SPContext.Current, false, "" );
55:
56:             CloseForm();
57:         }
58:     }
59: }

We need to modify the “Elements.xml” file of the module named “Workflow 1 Forms”.

1: <?xml version="1.0" encoding="utf-8"?>
2: <Elements xmlns="http://schemas.microsoft.com/sharepoint/">
3:  <Module Name="Workflow 1 Forms" Url="Workflow1Forms" RootWebOnly="FALSE">
4:  <File Path="Workflow 1 FormsTask1Form.aspx" Url="Task1Form.aspx" />
5:  </Module>
6: </Elements> 

This specifies there to store the “Task1Form.aspx” file in the site structure.

9. In the next step we create the task list that will contain our workflow tasks.

First create a “List Definition” project item named “Workflow 1 Tasks”.

image

Use “Workflow 1 Tasks” as name of the list definition and “Tasks” as base type. Check “Add a list instance…”.

image

10. Now open “Elements.xml” of the new list definition project item.

image

We need to change the identifier of the list type we create! – It must be “107”. This is the list template ID for workflow tasks lists in SharePoint. The workflow designer will search for a list with this type inside the site where a new workflow will be created.

Here is the content of “Elements.xml” after our modification:

1: <?xml version="1.0" encoding="utf-8"?>
2: <Elements xmlns="http://schemas.microsoft.com/sharepoint/">
3:  <ListTemplate
4:  Name="Workflow 1 Tasks"
5:  Type="107"
6:  BaseType="0"
7:  OnQuickLaunch="TRUE"
8:  SecurityBits="11"
9:  Sequence="360"
10:  DisplayName="Workflow 1 Tasks"
11:  Description="Tasks of Workflow 1"
12:  Image="/_layouts/images/itgen.png"/>
13: </Elements>  

11. Now we modify the “Elements.xml” file of the list instance that will be created during deployment:

image

Here we also need to modify the type identifier to “107”. Furthermore we change the list url: “Lists/Workflow1Tasks”.

Here is the complete content of “Elements.xml”:

1: <?xml version="1.0" encoding="utf-8"?>
2: <Elements xmlns="http://schemas.microsoft.com/sharepoint/">
3:  <ListInstance Title="Workflow 1 Tasks"
4:  OnQuickLaunch="TRUE"
5:  TemplateType="107"
6:  Url="Lists/Workflow1Tasks"
7:  Description="Tasks of Workflow 1">
8:  </ListInstance>
9: </Elements> 

In a “real world” scenario we would prevent the list from being listed on the Quick Launch bar. So the corresponding parameter must be set to “FALSE”.

12. Now we need to modify the “Schema.xml” file of the list definition.

image

First we set the list type to “107” and configure some other attributes:

1: <List xmlns:ows="Microsoft SharePoint" Title="Workflow 1 Tasks"
2:  FolderCreation="FALSE" Direction="$Resources:Direction;"
3:  EnableContentTypes="TRUE" VersioningEnabled="TRUE"
4:  Url="Lists/Workflow1Tasks"
5:  Type="107" BaseType="0"
6:  xmlns="http://schemas.microsoft.com/sharepoint/">
7: […]

Now remove the the content types defined in the “ContentTypes” tag in the “schema.xml” file.

image

Insert this content type definition into the “ContentTypes” tag:

1:  <ContentType ID="0x01080100FFbc98c2529347a5886b8d2576b954ef"
2:  Name="Workflow 1 Tasks 1"
3:  Group="Workflow 1 Tasks"
4:  Description="Content Type of Tasks 1 of Workflow 1">
5:  <FieldRefs>
6:  <FieldRef ID="{2FE15855-3CAB-44A6-AB29-1600204FCA20}" Name="Workflow1Task1_Test1" DisplayName="Test1" Required="FALSE" Hidden="FALSE" ReadOnly="FALSE" PITarget="" PrimaryPITarget="" PIAttribute="" PrimaryPIAttribute="" Aggregation="" Node="" />
7:  <FieldRef ID="{517B22A5-1B89-4C24-82BE-3D4FD99645BC}" Name="Workflow1Task1_Test2" DisplayName="Test2" Required="FALSE" Hidden="FALSE" ReadOnly="FALSE" PITarget="" PrimaryPITarget="" PIAttribute="" PrimaryPIAttribute="" Aggregation="" Node="" />
8:  <FieldRef ID="{3ECFF1FE-F56B-4556-8805-4570D9422FF4}" Name="Workflow1Task1_Test3" DisplayName="Test3" Required="FALSE" Hidden="FALSE" ReadOnly="FALSE" PITarget="" PrimaryPITarget="" PIAttribute="" PrimaryPIAttribute="" Aggregation="" Node="" />
9:
10:  <FieldRef ID="{c042a256-787d-4a6f-8a8a-cf6ab767f12d}" Name="ContentType" />
11:  <FieldRef ID="{fa564e0f-0c70-4ab9-b863-0177e6ddd247}" Name="Title" Required="TRUE" ShowInNewForm="TRUE" ShowInEditForm="TRUE" />
12:  <FieldRef ID="{c3a92d97-2b77-4a25-9698-3ab54874bc6f}" Name="Predecessors" />
13:  <FieldRef ID="{a8eb573e-9e11-481a-a8c9-1104a54b2fbd}" Name="Priority" />
14:  <FieldRef ID="{c15b34c3-ce7d-490a-b133-3f4de8801b76}" Name="Status" />
15:  <FieldRef ID="{d2311440-1ed6-46ea-b46d-daa643dc3886}" Name="PercentComplete" />
16:  <FieldRef ID="{53101f38-dd2e-458c-b245-0c236cc13d1a}" Name="AssignedTo" />
17:  <FieldRef ID="{7662cd2c-f069-4dba-9e35-082cf976e170}" Name="Body" />
18:  <FieldRef ID="{64cd368d-2f95-4bfc-a1f9-8d4324ecb007}" Name="StartDate" />
19:  <FieldRef ID="{cd21b4c2-6841-4f9e-a23a-738a65f99889}" Name="DueDate" />
20:  <FieldRef ID="{58ddda52-c2a3-4650-9178-3bbc1f6e36da}" Name="WorkflowLink" />
21:  <FieldRef ID="{16b6952f-3ce6-45e0-8f4e-42dac6e12441}" Name="OffsiteParticipant" />
22:  <FieldRef ID="{4a799ba5-f449-4796-b43e-aa5186c3c414}" Name="OffsiteParticipantReason" />
23:  <FieldRef ID="{18e1c6fa-ae37-4102-890a-cfb0974ef494}" Name="WorkflowOutcome" />
24:  <FieldRef ID="{e506d6ca-c2da-4164-b858-306f1c41c9ec}" Name="WorkflowName" />
25:  <FieldRef ID="{ae069f25-3ac2-4256-b9c3-15dbc15da0e0}" Name="GUID" />
26:  <FieldRef ID="{8d96aa48-9dff-46cf-8538-84c747ffa877}" Name="TaskType" />
27:  <FieldRef ID="{17ca3a22-fdfe-46eb-99b5-9646baed3f16}" Name="FormURN" />
28:  <FieldRef ID="{78eae64a-f5f2-49af-b416-3247b76f46a1}" Name="FormData" />
29:  <FieldRef ID="{8cbb9252-1035-4156-9c35-f54e9056c65a}" Name="EmailBody" />
30:  <FieldRef ID="{47f68c3b-8930-406f-bde2-4a8c669ee87c}" Name="HasCustomEmailBody" />
31:  <FieldRef ID="{cb2413f2-7de9-4afc-8587-1ca3f563f624}" Name="SendEmailNotification" />
32:  <FieldRef ID="{4d2444c2-0e97-476c-a2a3-e9e4a9c73009}" Name="PendingModTime" />
33:  <FieldRef ID="{35363960-d998-4aad-b7e8-058dfe2c669e}" Name="Completed" />
34:  <FieldRef ID="{1bfee788-69b7-4765-b109-d4d9c31d1ac1}" Name="WorkflowListId" />
35:  <FieldRef ID="{8e234c69-02b0-42d9-8046-d5f49bf0174f}" Name="WorkflowItemId" />
36:  <FieldRef ID="{1c5518e2-1e99-49fe-bfc6-1a8de3ba16e2}" Name="ExtendedProperties" />
37:  </FieldRefs>
38:  <XmlDocuments>
39:  <XmlDocument NamespaceURI="http://schemas.microsoft.com/sharepoint/v3/contenttype/forms">
40:  <FormTemplates xmlns="http://schemas.microsoft.com/sharepoint/v3/contenttype/forms">
41:  <Display>ListForm</Display>
42:  <Edit>ListForm</Edit>
43:  <New>ListForm</New>
44:  </FormTemplates>
45:  </XmlDocument>
46:  <XmlDocument NamespaceURI="http://schemas.microsoft.com/sharepoint/v3/contenttype/forms/url">
47:  <FormUrls xmlns="http://schemas.microsoft.com/sharepoint/v3/contenttype/forms/url">
48:  <Edit>Workflow1Forms/Task1Form.aspx</Edit>
49:  </FormUrls>
50:  </XmlDocument>
51:  </XmlDocuments>
52:  </ContentType>
53:
54:

You see the “FormUrls” tag? Inside this tag we specify our custom form template we created before.

The new content type is derived from the “Workflow Task” content type 0x010801. – In the “FieldRefs” section we add our fields we need inside the workflow.

13. Now we need to add the field definitions of our custom fields to the “Schema.xml”. Copy them from the “Elements.xml”  file of project item “Workflow 1 Fields” into the “Fields” tag of “Schema.xml”:

image

Furthermore you need to add a field definition for the field “Completed”:

1:  <Field ID="{35363960-D998-4aad-B7E8-058DFE2C669E}" Name="Completed"
2:  SourceID="http://schemas.microsoft.com/sharepoint/v3"
3:  StaticName="Completed" Group="Base Columns" Type="Boolean"
4:  DisplayName="Completed" Hidden="TRUE" Sealed="TRUE"
5:  Overwrite="TRUE" xmlns="http://schemas.microsoft.com/sharepoint/">
6:  <Default>FALSE</Default>
7:  </Field> 

14. Now deploy the project.

While deployment you may get this dialog:

image

Check “Do not prompt…”. Press “Resolve Automatically”  – it’s your only option Smile.

15. Have a look into the site using the browser. – We will test our “Edit” form. Remember that we did not specify special “New” form or “Display” form. This you could do the same way as you created the “Edit” form.

We see our lists in the Quick Launch.

image

Open the “Workflow 1 Tasks” list. On the Ribbon open the “Items” tab. We see our Content Type in the New Item submenu:

image

Create an item of this type. You see a standard “New” form and on it you see our three “Test” fields:

image

Enter some data and press  “Save”.

image

Open the item  in “Edit” form. Now you should see our custom list form.

image

If you click “Save As Draft” your changes will be stored in the task item. If you click “Complete Task” two item fields will be changed in addition to the changes made in the form: It sets “Status” to “Tasks_Completed” and “% Complete” to “100”. You can see this in the Code Behind file of the list form.

Test all buttons.

After “Complete Task”:

image

You see: “% Complete” is set to “100 %”.

So far our projects works as expected.

See Part 2 for the next steps… There I will show you how to create a simple Sequential Workflow that uses our Task Form.

Here is part 2: https://blog.kenaro.com/2011/03/30/walkthrough-creating-a-simple-sequential-workflow-with-a-custom-task-form-in-sharepoint-2010-using-visual-studio-2010-part-2-of-2/

Demo project: Excel Export feature for SharePoint 2010

I’ve uploaded another private demo project. It was planned as part of an SharePoint solution I liked to create but I cannot finalize this project. So I publish this project as “stand alone” project…. You may find it useful.

You are invited to use / develop / update the project! Every help is welcome!

You find the source code here:

http://spexcelexport.codeplex.com/

The project is ALPHA!!!

The intention of the project is to create a possibility to export SharePoint lists to "plain" Excel files. Not the kind of Excel files you can download by using the SharePoint standard functionality: With that you download a "linked" Excel file that contains a permanent connection the SharePoint. It’s a query. – With my project you’ll download a real XLSX file. – And you have the possibility to store an template file that contains formatting instructions.

It’s not finished but it works! – The test project included in the source code demonstrates the feature. Use "Test List 1". (Not "Test List 2".)

Some screenshots:

This is the “Test List 1”:

image

There is a link in the upper right. This you can use to download the Excel file:

image

When you click the link you get the well known download window:

image

Clicking “Open” will open the Excel Viewer – or the “real” Excel (that I do not have on my dev machine).

image

In Excel you can resize the “C” column.

May you have seen it: There is an error in the solution: Date values are not exported correctly. There is a gap of 1 day…

The goal is to implement a Ribbon button.

See the hidden list:

image

Have a look into the single Excel file:

image

Ok… Lots of work to do Smile

Sample Visual Studio 2010 project for creating a custom SharePoint 2010 Ribbon tab on runtime (!)

The related articles on my blog are:


I wanted to create a sample project to show you who you can create a custom SharePoint 2010 Ribbon tab at runtime! – Especially: How to active the custom ribbon tab on “page loaded” (no need to click it!) So this article is an addition to my explanations in my previous article “How To Activate SharePoint Ribbon Tab by JavaScript Code”.

You can download the project from Codeplex:

http://spcustomribbondemo.codeplex.com

You are invited to download / update / improve the project! – I’d like to insert more samples in the project about how to deploy Ribbon customizations. In the sample I created a ribbon in a custom list view web page. (You’ll see in the code).

To use the project you need a SharePoint web application named “http://sharepoint.local” and a site collection named “ribbon”.

Deploy the project.

Open the SharePoint site and it’s list in your browser.

image

You’ll see:

image

This tab is actived automatically on page load!!!

The source code of my project is inspired by some blog post of this people:

These are the steps of development I’ve done:

1. Create an empty SharePoint 2010 project in Visual Studio 2010

2. Create an “List Definition” project item.

3. Add a “Application Page” project item.

4. Move the new application page to the “List Definition” project item.

5. Change the base class to “WebPartPage”

6. Modify the “Page” tag of the aspx page: replace “DynamicalMasterPageFile” with “MasterPageFile”

7. Replace the content of the aspx file with this code:

 

1: <asp:Content  ContentPlaceHolderID="PlaceHolderAdditionalPageHead"  runat="server"> 

2: </asp:Content> 

3:

4: <asp:Content  ContentPlaceHolderID="PlaceHolderMain"  runat="server"> 

5:     <WebPartPages:WebPartZone  runat="server"  FrameType="None"  ID="Main2"  Title="loc:Main"> 

6:         <ZoneTemplate> 

7:         </ZoneTemplate> 

8:     </WebPartPages:WebPartZone> 

9: </asp:Content> 

10: <asp:Content  ContentPlaceHolderID="PlaceHolderPageTitle"  runat="server"> 

11: </asp:Content> 

12: <asp:Content  ContentPlaceHolderID="PlaceHolderPageTitleInTitleArea"  runat="server"> 

13: </asp:Content>

14:

8. Insert the following code into the CS file of the ASPX file. This code will create the custom Ribbon tab. (The Ribbon tab XML definition code could be created dynamically!!!)

 

1: using  System;

2: using  System.Security.Permissions;

3: using  Microsoft.SharePoint.Security;

4: using  Microsoft.SharePoint.WebPartPages;

5: using  Microsoft.SharePoint;

6: using  Microsoft.SharePoint.WebControls;

7: using  System.Web.UI.WebControls.WebParts;

8: using  System.Diagnostics;

9: using  System.Xml;

10: using  System.Collections.Generic;

11: using  System.Reflection;

12: using  System.Text;

13:

14: namespace  ik.SharePoint2010.SPCustomTabRibbonDemo.Layouts.SPCustomTabRibbonDemo

15: {

16:     public  partial  class  AllItems  : WebPartPage 

17:     {

18:         protected  void  Page_Load(object  sender, EventArgs  e)

19:         {

20:         }

21:

22:         private  string  tab = @" 

23:           <Tab Id=""ik.SharePoint2010.Ribbon.CustomTab"" Title=""ik-ribbon"" Description=""Ingo's Command Group"" Sequence=""501""> 

24:             <Scaling Id=""ik.SharePoint2010.Ribbon.CustomTab.Scaling""> 

25:               <MaxSize Id=""ik.SharePoint2010.Ribbon.CustomTab.Group1.MaxSize"" 

26:                        GroupId=""ik.SharePoint2010.Ribbon.CustomTab.Group1"" 

27:                        Size=""OneLarge""/> 

28:               <Scale Id=""ik.SharePoint2010.Ribbon.CustomTab.Group1.Scaling.CustomTabScaling"" 

29:                      GroupId=""ik.SharePoint2010.Ribbon.CustomTab.Group1"" 

30:                      Size=""OneLarge""/> 

31:               <MaxSize Id=""ik.SharePoint2010.Ribbon.CustomTab.Group2.MaxSize"" 

32:                        GroupId=""ik.SharePoint2010.Ribbon.CustomTab.Group2"" 

33:                        Size=""OneLarge""/> 

34:               <Scale Id=""ik.SharePoint2010.Ribbon.CustomTab.Group2.Scaling.CustomTabScaling"" 

35:                      GroupId=""ik.SharePoint2010.Ribbon.CustomTab.Group2"" 

36:                      Size=""OneLarge""/> 

37:               <MaxSize Id=""ik.SharePoint2010.Ribbon.CustomTab.Group3.MaxSize"" 

38:                        GroupId=""ik.SharePoint2010.Ribbon.CustomTab.Group3"" 

39:                        Size=""OneLarge""/> 

40:               <Scale Id=""ik.SharePoint2010.Ribbon.CustomTab.Group3.Scaling.CustomTabScaling"" 

41:                      GroupId=""ik.SharePoint2010.Ribbon.CustomTab.Group3"" 

42:                      Size=""OneLarge""/> 

43:             </Scaling> 

44:             <Groups Id=""ik.SharePoint2010.Ribbon.CustomTab.Groups""> 

45:               <Group Id=""ik.SharePoint2010.Ribbon.CustomTab.Group1"" 

46:                      Description=""Ingo's Custom Ribbon Demo 1"" 

47:                      Title=""Ingo's Custom Ribbon Demo 1"" 

48:                      Sequence=""10"" 

49:                      Template=""ik.SharePoint2010.Ribbon.Templates.OneLarge""> 

50:                 <Controls Id=""ik.SharePoint2010.Ribbon.CustomTab.Group1.Controls""> 

51:                   <Button Id=""ik.SharePoint2010.Ribbon.CustomTab.Group1.Button1"" 

52:                           Command=""ik.SharePoint2010.Command.Button1"" 

53:                           Description=""Do something"" 

54:                           Sequence=""10"" 

55:                           LabelText=""Do something"" 

56:                           Image16by16=""/_layouts/images/DOC16.GIF"" 

57:                           Image32by32=""/_layouts/images/DOC32.GIF"" 

58:                           TemplateAlias=""cust1""/> 

59:                 </Controls> 

60:               </Group> 

61:               <Group Id=""ik.SharePoint2010.Ribbon.CustomTab.Group3"" 

62:                      Description=""Ingo's Custom Ribbon Demo 3"" 

63:                      Title=""Ingo's Custom Ribbon Demo 3"" 

64:                      Sequence=""30"" 

65:                      Template=""ik.SharePoint2010.Ribbon.Templates.OneLarge""> 

66:                 <Controls Id=""ik.SharePoint2010.Ribbon.CustomTab.Group3.Controls""> 

67:                   <Button Id=""ik.SharePoint2010.Ribbon.CustomTab.Group3.Button3"" 

68:                           Command=""ik.SharePoint2010.Command.Button3"" 

69:                           Description=""Do more"" 

70:                           Sequence=""10"" 

71:                           LabelText=""Do more"" 

72:                           Image32by32=""/_layouts/images/PPEOPLE.GIF"" 

73:                           TemplateAlias=""cust1""/> 

74:                 </Controls> 

75:               </Group> 

76:               <Group Id=""ik.SharePoint2010.Ribbon.CustomTab.Group2"" 

77:                      Description=""Ingo's Custom Ribbon Demo 2"" 

78:                      Title=""Ingo's Custom Ribbon Demo 2"" 

79:                      Sequence=""20"" 

80:                      Template=""ik.SharePoint2010.Ribbon.Templates.OneLarge""> 

81:                 <Controls Id=""ik.SharePoint2010.Ribbon.CustomTab.Group2.Controls""> 

82:                   <Button Id=""ik.SharePoint2010.Ribbon.CustomTab.Group2.Button2"" 

83:                           Command=""ik.SharePoint2010.Command.Button2"" 

84:                           Description=""Do nothing"" 

85:                           Sequence=""10"" 

86:                           LabelText=""Do nothing"" 

87:                           Image32by32=""/_layouts/images/PPEOPLE.GIF"" 

88:                           TemplateAlias=""cust1""/> 

89:                 </Controls> 

90:               </Group> 

91:             </Groups> 

92:           </Tab> 

93:

94: " ;

95:         private  string  tabTempl = @" 

96:           <GroupTemplate Id=""ik.SharePoint2010.Ribbon.Templates.OneLarge""> 

97:             <Layout Title=""OneLarge"" LayoutTitle=""OneLarge""> 

98:               <Section Alignment=""Top"" Type=""OneRow""> 

99:                 <Row> 

100:                   <ControlRef DisplayMode=""Large"" TemplateAlias=""cust1"" /> 

101:                 </Row> 

102:               </Section> 

103:             </Layout> 

104:           </GroupTemplate> 

105: " ;

106:

107:         protected  override  void  OnPreRender(EventArgs  e)

108:         {

109:             //Debugger.Break(); 

110:             SPRibbon  r = Microsoft.SharePoint.WebControls.SPRibbon .GetCurrent(this .Page);

111:             XmlDocument  rx = new  XmlDocument ();

112:             rx.LoadXml(tab);

113:             r.RegisterDataExtension(rx.FirstChild, "Ribbon.Tabs._children" );

114:             rx.LoadXml(tabTempl);

115:             r.RegisterDataExtension(rx.FirstChild, "Ribbon.Templates._children" );

116:

117:             List <IRibbonCommand > commands = new  List <IRibbonCommand >();

118:             commands.Add(new  SPRibbonCommand ("ik.SharePoint2010.Command.Button1" , "ikSharePoint2010CommandButton1Action()" , "true" ));

119:             commands.Add(new  SPRibbonCommand ("ik.SharePoint2010.Command.Button2" , "ikSharePoint2010CommandButton2Action()" , "ikSharePoint2010CommandButton2Enable()" ));

120:             commands.Add(new  SPRibbonCommand ("ik.SharePoint2010.Command.Button3" , "ikSharePoint2010CommandButton3Action()" , "ikSharePoint2010CommandButton3Enable()" ));

121:

122:             SPRibbonScriptManager  rsm = new  SPRibbonScriptManager ();

123:

124:             ScriptLink .RegisterScriptAfterUI(this .Page, "SP.Runtime.js" , false , true );

125:             ScriptLink .RegisterScriptAfterUI(this .Page, "SP.js" , false , true );

126:             ScriptLink .RegisterScriptAfterUI(this .Page, "CUI.js" , false , true );

127:             ScriptLink .RegisterScriptAfterUI(this .Page, "SP.Ribbon.js" , false , true );

128:             ScriptLink .RegisterScriptAfterUI(this .Page, "ik.SharePoint2010.SPCustomTabRibbonDemo/ikactions.js" , false , true );

129:             ScriptLink .RegisterScriptAfterUI(this .Page, "ik.SharePoint2010.SPCustomTabRibbonDemo/ikribbon.UI.js" , false , true );

130:

131:             rsm.RegisterGetCommandsFunction(this .Page, "getGlobalCommands" , commands);

132:             rsm.RegisterCommandEnabledFunction(this .Page, "commandEnabled" , commands);

133:             rsm.RegisterHandleCommandFunction(this .Page, "handleCommand" , commands);

134:

135:             string  script = @" 

136:                 <script language=""javascript"" defer=""true""> 

137:                 //<![CDATA[ 

138:                    function ikribbonInit1() {  

139:                      ikribbonInit(); 

140:                    } 

141:                    ExecuteOrDelayUntilScriptLoaded(ikribbonInit1,'); 

142:                 //]]> 

143:                 </script>" ;

144:             ClientScript.RegisterClientScriptBlock(this .GetType(), "InitPageComponent" , script);

145:

146:             r.MakeTabAvailable("ik.SharePoint2010.Ribbon.CustomTab" );

147:             r.SetInitialTabId("ik.SharePoint2010.Ribbon.CustomTab" , "" );

148:             base .OnPreRender(e);

149:         }

150:

151:         protected  override  void  OnInitComplete(EventArgs  e)

152:         {

153:             base .OnInitComplete(e);

154:         }

155:     }

156: }

157:

158:

9. You need two JavaScript files in the project’s sub folder in the SharePoint’s hive folder “Layouts”.

This file contains code for the Ribbon:

 

1: function  ULS_SP() {

2:     if  (ULS_SP.caller) {

3:         ULS_SP.caller.ULSTeamName = "Windows SharePoint Services 4" ;

4:         ULS_SP.caller.ULSFileName = "ikribbon.UI.js" ;

5:     }

6: }

7:

8: Type.registerNamespace(< span> );

9:

10: //  Page Component 

11: ikribbon.UI.PageComponent = function  () {

12:     ULS_SP();

13:     ikribbon.UI.PageComponent.initializeBase(this );

14: }

15: ikribbon.UI.PageComponent.initialize = function  () {

16:     ULS_SP();

17:     ExecuteOrDelayUntilScriptLoaded(Function.createDelegate(null , ikribbon.UI.PageComponent.initializePageComponent), < span> );

18: }

19: ikribbon.UI.PageComponent.initializePageComponent = function  () {

20:     ULS_SP();

21:     var  ribbonPageManager = SP.Ribbon.PageManager.get_instance();

22:     if  (null  !== ribbonPageManager) {

23:         ribbonPageManager.addPageComponent(ikribbon.UI.PageComponent.instance);

24:         ribbonPageManager.get_focusManager().requestFocusForComponent(ikribbon.UI.PageComponent.instance);

25:     }

26: }

27: ikribbon.UI.PageComponent.refreshRibbonStatus = function  () {

28:     SP.Ribbon.PageManager.get_instance().get_commandDispatcher().executeCommand(Commands.CommandIds.ApplicationStateChanged, null );

29: }

30: ikribbon.UI.PageComponent.prototype = {

31:     getFocusedCommands: function  () {

32:         ULS_SP();

33:         return  [];

34:     },

35:     getGlobalCommands: function  () {

36:         ULS_SP();

37:         return  getGlobalCommands();

38:     },

39:     isFocusable: function  () {

40:         ULS_SP();

41:         return  true ;

42:     },

43:     receiveFocus: function  () {

44:         ULS_SP();

45:         return  true ;

46:     },

47:     yieldFocus: function  () {

48:         ULS_SP();

49:         return  true ;

50:     },

51:     canHandleCommand: function  (commandId) {

52:         ULS_SP();

53:         return  commandEnabled(commandId);

54:     },

55:     handleCommand: function  (commandId, properties, sequence) {

56:         ULS_SP();

57:         return  handleCommand(commandId, properties, sequence);

58:     }

59: }

60:

61: var  ikribbonActiveInterval = null ;

62:

63: function  ikribbonActiveRibbonTab() {

64:     try  {

65:         window.clearInterval(ikribbonActiveInterval);

66:

67:         if  (typeof  (_ribbonStartInit) == "function" ) {

68:             _ribbonStartInit(< span> , false , null );

69:         }

70:

71:         if  (true  && typeof  (_ribbonReadyForInit) == < span>  && !_ribbonReadyForInit()) {

72:             ikribbonActiveInterval = window.setInterval("ikribbonActiveRibbonTab()" , 100);

73:         }

74:     } catch  (e2) {

75:     };

76: };

77:

78: function  ikribbonInit() {

79:     alert(< span> );

80:     ikribbon.UI.PageComponent.registerClass(< span> , CUI.Page.PageComponent);

81:     ikribbon.UI.PageComponent.instance = new  ikribbon.UI.PageComponent();

82:     ikribbon.UI.PageComponent.initialize();

83:

84:     ExecuteOrDelayUntilScriptLoaded(ikribbonActiveRibbonTab, < span> );

85: }

86:

87: NotifyScriptLoadedAndExecuteWaitingJobs("ikribbon.UI.js" );

88:

89:

90:

91:

This file contains code for the actions executed on clicking the custom Ribbon buttons:

 

1: function  ikSharePoint2010CommandButton1Action() {

2:     alert("Button 1 pressed" );

3: }

4:

5: function  ikSharePoint2010CommandButton1Enable() {

6:     return  true ;

7: }

8:

9: function  ikSharePoint2010CommandButton2Action() {

10:     alert("Button 2 pressed" );

11: }

12:

13: function  ikSharePoint2010CommandButton2Enable() {

14:     return  true ;

15: }

16:

17: function  ikSharePoint2010CommandButton3Action() {

18:     alert("Button 3 pressed" );

19: }

20:

21: function  ikSharePoint2010CommandButton3Enable() {

22:     return  true ;

23: }

24:

25:

10. Modify the list definitions “schema.xml” file: Edit the following line:

<View BaseViewID=”1″ Type=”HTML” WebPartZoneID=”Main2″ DisplayName=”$Resources:core,objectiv_schema_mwsidcamlidC24;”

DefaultView=”TRUE” MobileView=”TRUE” MobileDefaultView=”TRUE” ImageUrl=”/_layouts/images/generic.png” Url=”AllItems.aspx”>

Remove the SetupPath attribute!

11. Set the view pages “DeploymentType” property to “NoDeployment”:

image

12. That’s all Hot smile