zevenseas


 

Social Computing Overview and a short status update

Social Computing Overview
If you missed us at the SharePoint Connections in Amsterdam that was held on the 18th and 19th of January, here is a chance to see our experimental session about the new social computing features that are available in SharePoint 2010.

So to answer the first question “why is it experimental?’, it is because we brought in a server, two laptops, an extra projector and a hub (something you should actually never do when presenting or doing a demo, especially with beta software ;)

First Daniel talks about what Social Computing really is and what all the fuzz is about (which he does rather excellent if I say so myself :)

image

Then to start the demo.. Daniel writes a blog post and shows us how easy it is to Tag content in 2010..

image

Next it’s demo time for Mark and me.. Mark is showing the new enhancements of the MySite which features the Network page (which shows all the activities you are following from your colleagues and tags) and the Profile page (and during the demo something funny happens with Mark’s laptop battery ;))..

image

Then Mark fires up a OneNote book and saves that into his MySite and the ‘experimental’ is about to start, at that moment I join the session and open up Mark’s OneNote using the new Office WebApps to collaborate with each other real-time (with a 8sec delay..)

image

Hope I got you excited to watch it and see us in action.. if so, then please go to Channel 9 and watch it! ;) Kudos to Matthijs Hoekstra (@mahoekst) from Microsoft for letting us do this experimental demo. Also a huge thanks to the guys responsible for the audio/video who did an excellent job getting all the stuff exactly right (I’d never expected our projector to be captured so good and nice like it did!)

Status update
So what about the status update you might wonder, well recently I finished a project and as of today I have no projects to do. So if you think you can use me on your project then please ping me at robin at zevenseas.com!

Updated : FeatureBlocker

Remember I published the FeatureBlocker tool a couple of months ago? If you don’t, here’s a short description in what the tool does:

Using the FeatureBlocker, you can prevent users from activating features within the SharePoint UI. There are three types of ‘prevent’ actions : block the ‘activate/deactivate’ button, hide the entire feature, redirect the user when clicking on the activate/deactivate button.

Check out zevenseas Feature Blocker and Want to prevent users from activating certain features? about the history of the tool..

So, what’s changed? Well.. by a popular demand (@UncleJohnsBand) I’ve added the option to ‘block’ features per feature-scope.. Next to that I’ve also cleaned up the UI from the Settings page, I moved the configuration of the ‘block’ type into a new page and the creation of a list where you can store the ‘requests’ of the features as well. Below is the screenshot of the configuration page:

image

Let me know what you think of it and if you have additional requirements or feedback don’t hesitate to contact me ;)

Where can you find it? At http://www.codeplex.com/zsfeatureblocker !

Where is the Save button?

As we were prepping for the demo that we held at the SharePoint Connections conference in Amsterdam last week about “Social Computing Overview'”, one of the things that we wanted to demo was the online collaboration bit.

At first, we wanted to show Word 2010 client and the Word 2010 WebApp and the interaction between those two. But, as it turned out, you have to save every time you want to ‘share’ your part of the document to the other person. Then, just for the fun of it, I took a look at OneNote and in particular the OneNote WebApp..

I wrote something down and, of course, I wanted to save my document. First I looked in the upper bar for the well known blue disk icon.. but there was none.. so .. I opened up the “backstage” view (by clicking on “File”) and there I saw the menu option “Where’s the Save Button?”.. now at this moment I was already laughing out loud! Somebody in the Office team must have a good sense of humor to include these kind of bit smart-ass menu options ;)

image

So what happens if you click on it? Well, then you’re confronted with this dialog:

image

It’s surprising in a way why only Word does not have this feature because PowerPoint and Excel WebApp’s also have this ‘automatic’ save functionality. I mean, I can understand why it’s not in Word but for consistency sake it would be good to have it in there by default or something.

Do you live in India.. and do you love SharePoint?

Then wait no longer and contact us at bestinindia@zevenseas.com and send us your resume!

But only do so if :

  1. You have been working with SharePoint for more than 3 years.
  2. You are a C-Sharper.
  3. You are in Information Technology because you love it and can prove it!
  4. You are a great communicator, and a team player.
  5. If you think India (and the Netherlands) beat Australia at cricket! ;)

Love to hear from you!

Current Navigation, SPNavigationNodes and the AreaNavigationSettings page

I was at a customer recently where I had the request that the current navigation of a team site should have a particular ordering. In this ‘current’ navigation, the navigation consisted of links to lists on the specific site to links to sub sites of that site. I knew that in the AreaNavigationSettings.aspx page (see screenshot) you could define such a ordering just by moving links up and down and also check the checkbox to display subsites. So, I thought.. ha that’s easy! I’m just going to check what kind of code is behind that page.. use that et voila.. Robin is a happy man.. :)

image

Boy.. was I wrong.. maybe it was my bad that I couldn’t really figure out what they are doing behind the scenes when I used Reflector to see how the code looked like but maybe it wasn’t ;) So instead of staring at the code and trying to make it work in my dev environment I turned to Google again and did some specific searches and then I came across my lifesaver Gary Lapointe with this post : More Site Navigation Settings Commands.

Apparently, there is no real way of ‘modifying’ the navigation by just moving nodes around and then save the collection if you want make use of the ability of displaying subsites by making use of the IncludeSubSitesInNavigation bool. The thing is that you will have to delete the current nodes and recreate them, in the proper order, and save that back (please correct me if I’m wrong!).

To continue, I used his code and modified it a bit so I wouldn’t need to pass a xml document with Nodes but just a List<Nodes> to create my navigation. Next to that, I was only interested in modifying the Current Navigation and not the Global Navigation so I stripped that bit out.

Here’s the my custom NavigationNode class and the method to create the navigation:

   1: public class NavigationNode
   2: {
   3:     public string Title { get; set; }
   4:     public string Url { get; set; }
   5:     public NodeTypes NodeType { get; set; }
   6:     public SPNavigationNodeCollection NavigationNodeCollection { get; set; }
   7:  
   8:     public NavigationNode(string title, string url, NodeTypes nodeType, SPNavigationNodeCollection collection)
   9:     {
  10:         Title = title;
  11:         Url = url;
  12:         NodeType = nodeType;
  13:         NavigationNodeCollection = collection;
  14:     }
  15: }
   1: protected void CreateNavigation()
   2: {
   3:     PublishingWeb publishingWeb = PublishingWeb.GetPublishingWeb(CurrentWeb);
   4:     List<NavigationNode> nodeCollection = new List<NavigationNode>();
   5:     nodeCollection.Add(new NavigationNode("Home", "Pages/Default.aspx", NodeTypes.AuthoredLink, publishingWeb.CurrentNavigationNodes));
   6:     nodeCollection.Add(new NavigationNode("Discussions", "Lists/Discussions/AllItems.aspx", NodeTypes.AuthoredLink, publishingWeb.CurrentNavigationNodes));
   7:     nodeCollection.Add(new NavigationNode("Documents", "Shared Documents/Forms/AllItems.aspx", NodeTypes.AuthoredLink, publishingWeb.CurrentNavigationNodes));
   8:     nodeCollection.Add(new NavigationNode("Wiki", CurrentWeb.ServerRelativeUrl + "/Wiki", NodeTypes.Area, publishingWeb.CurrentNavigationNodes));
   9:     nodeCollection.Add(new NavigationNode("Calendar", "Meetings/Lists/Kalender/calendar.aspx", NodeTypes.AuthoredLinkToWeb, publishingWeb.CurrentNavigationNodes));                      
  10:     SetNavigation(CurrentWeb, nodeCollection, true, false, true, true);
  11:     publishingWeb.Update();
  12: }

And then here is my, slightly, modified version of Gary’s awesome code :

   1: /// Original source is from Gary Lapointe, I've only done a modification so that it accepts a List with NavigationNodes instead of a XML file
   2:        /// <summary>
   3:        /// Sets the navigation.
   4:        /// </summary>
   5:        /// <param name="site">The site.</param>
   6:        /// <param name="web">The web site.</param>
   7:        /// <param name="nodeCollection">A list containing all the nodes.</param>
   8:        /// <param name="showSubSites">if set to <c>true</c> [show sub sites].</param>
   9:        /// <param name="showPages">if set to <c>true</c> [show pages].</param>
  10:        /// <param name="deleteExistingGlobal">if set to <c>true</c> [delete existing global nodes].</param>
  11:        /// <param name="deleteExistingCurrent">if set to <c>true</c> [delete existing current nodes].</param>
  12:        public static void SetNavigation(SPWeb web, List<NavigationNode> nodeCollection, bool showSubSites, bool showPages, bool deleteExistingGlobal, bool deleteExistingCurrent)
  13:        {
  14:            PublishingWeb pubweb = PublishingWeb.GetPublishingWeb(web);
  15:  
  16:            // First need to set whether or not we show sub-sites and pages
  17:            pubweb.IncludeSubSitesInNavigation = showSubSites;
  18:            pubweb.IncludePagesInNavigation = showPages;
  19:            pubweb.Update();
  20:  
  21:            List<SPNavigationNode> existingGlobalNodes = new List<SPNavigationNode>();
  22:            List<SPNavigationNode> existingCurrentNodes = new List<SPNavigationNode>();
  23:            // We can't delete the navigation items until we've added the new ones so store the existing 
  24:            // ones for later deletion (note that we don't have to store all of them - just the top level).
  25:            // I have no idea why this is the case - but when I tried to clear everything out first I got
  26:            // all kinds of funky errors that just made no sense to me - this works so....
  27:            foreach (SPNavigationNode node in pubweb.GlobalNavigationNodes)
  28:                existingGlobalNodes.Add(node);
  29:            foreach (SPNavigationNode node in pubweb.CurrentNavigationNodes)
  30:                existingCurrentNodes.Add(node);
  31:  
  32:            List<NavigationNode> newCurrentNodes = nodeCollection;
  33:  
  34:            if (newCurrentNodes.Count > 0)
  35:            {
  36:                pubweb.InheritCurrentNavigation = false;
  37:                pubweb.Update();
  38:            }
  39:            pubweb = PublishingWeb.GetPublishingWeb(web);
  40:  
  41:            // If we've got global or current nodes in the xml then the intent is to reset those elements.
  42:            // If we've also specified to delete any existing elements then we need to first hide all the
  43:            // sub-sites and pages (you can't delete them because they don't exist as a node).  Note that
  44:            // we are only doing this if showSubSites is true - if it's false we don't see them so no point
  45:            // in hiding them.  Any non-sub-site or non-page will be deleted after we've added the new nodes.
  46:            foreach (SPWeb tempWeb in pubweb.Web.Webs)
  47:            {
  48:                try
  49:                {
  50:                    if (newCurrentNodes.Count > 0 && deleteExistingCurrent && showSubSites)
  51:                    {
  52:                        pubweb.ExcludeFromNavigation(false, tempWeb.ID);
  53:                    }
  54:                }
  55:                finally
  56:                {
  57:                    tempWeb.Dispose();
  58:                }
  59:            }
  60:            pubweb.Update();
  61:  
  62:            // Now we need to add all the current nodes (if any)
  63:            AddNodes(pubweb, false, pubweb.CurrentNavigationNodes, newCurrentNodes);
  64:            // Update the web as the above may have made modifications
  65:            pubweb.Update();
  66:  
  67:            // Now delete all the previously existing current nodes.
  68:            if (newCurrentNodes.Count > 0 && deleteExistingCurrent)
  69:            {
  70:                foreach (SPNavigationNode node in existingCurrentNodes)
  71:                {
  72:                    node.Delete();
  73:                }
  74:            }
  75:        }
   1: /// <summary>
   2:        /// Adds the nodes.
   3:        /// </summary>
   4:        /// <param name="pubWeb">The publishing web.</param>
   5:        /// <param name="isGlobal">if set to <c>true</c> [is global].</param>
   6:        /// <param name="existingNodes">The existing nodes.</param>
   7:        /// <param name="newNodes">The new nodes.</param>
   8:        private static void AddNodes(PublishingWeb pubWeb, bool isGlobal, SPNavigationNodeCollection existingNodes, List<NavigationNode> newNodes)
   9:        {
  10:            if (newNodes.Count == 0)
  11:                return;
  12:  
  13:            for (int i = 0; i < newNodes.Count; i++)
  14:            {
  15:                NavigationNode newNodeXml = (NavigationNode)newNodes[i];
  16:                string url = newNodeXml.Url;
  17:                string title = newNodeXml.Title;
  18:                NodeTypes type = newNodeXml.NodeType;
  19:  
  20:                bool isVisible = true;
  21:  
  22:                if (type == NodeTypes.Area)
  23:                {
  24:                    // You can't just add an "Area" node (which represents a sub-site) to the current web if the
  25:                    // url does not correspond with an actual sub-site (the code will appear to work but you won't
  26:                    // see anything when you load the page).  So we need to check and see if the node actually
  27:                    // points to a sub-site - if it does not then change it to "AuthoredLinkToWeb".
  28:                    SPWeb web = null;
  29:                    try
  30:                    {
  31:                        string name = url.Trim('/');
  32:                        if (name.Length != 0 && name.IndexOf("/") > 0)
  33:                        {
  34:                            name = name.Substring(name.LastIndexOf('/') + 1);
  35:                        }
  36:                        try
  37:                        {
  38:                            // pubWeb.Web.Webs[] does not return null if the item doesn't exist - it simply throws an exception (I hate that!)
  39:                            web = pubWeb.Web.Webs[name];
  40:                        }
  41:                        catch (ArgumentException)
  42:                        {
  43:                        }
  44:                        if (web == null || !web.Exists || web.ServerRelativeUrl.ToLower() != url.ToLower())
  45:                        {
  46:                            // The url doesn't correspond with a sub-site for the current web so change the node type.
  47:                            // This is most likely due to copying navigation elements from another site
  48:                            type = NodeTypes.AuthoredLinkToWeb;
  49:                        }
  50:                        else if (web.Exists && web.ServerRelativeUrl.ToLower() == url.ToLower())
  51:                        {
  52:                            // We did find a matching sub-site so now we need to set the visibility
  53:                            if (isVisible)
  54:                                pubWeb.IncludeInNavigation(isGlobal, web.ID);
  55:                            else
  56:                                pubWeb.ExcludeFromNavigation(isGlobal, web.ID);
  57:                        }
  58:                    }
  59:                    finally
  60:                    {
  61:                        if (web != null)
  62:                            web.Dispose();
  63:                    }
  64:  
  65:                }
  66:                else if (type == NodeTypes.Page)
  67:                {
  68:                    // Adding links to pages has the same limitation as sub-sites (Area nodes) so we need to make
  69:                    // sure it actually exists and if it doesn't then change the node type.
  70:                    PublishingPage page = null;
  71:                    try
  72:                    {
  73:                        // Note that GetPublishingPages()[] does not return null if the item doesn't exist - it simply throws an exception (I hate that!)
  74:                        page = pubWeb.GetPublishingPages()[url];
  75:                    }
  76:                    catch (ArgumentException)
  77:                    {
  78:                    }
  79:                    if (page == null)
  80:                    {
  81:                        // The url doesn't correspond with a page for the current web so change the node type.
  82:                        // This is most likely due to copying navigation elements from another site
  83:                        type = NodeTypes.AuthoredLinkToPage;
  84:                        url = pubWeb.Web.Site.MakeFullUrl(url);
  85:                    }
  86:                    else
  87:                    {
  88:                        // We did find a matching page so now we need to set the visibility
  89:                        if (isVisible)
  90:                            pubWeb.IncludeInNavigation(isGlobal, page.ListItem.UniqueId);
  91:                        else
  92:                            pubWeb.ExcludeFromNavigation(isGlobal, page.ListItem.UniqueId);
  93:                    }
  94:                }
  95:  
  96:                // If it's not a sub-site or a page that's part of the current web and it's set to
  97:                // not be visible then just move on to the next (there is no visibility setting for
  98:                // nodes that are not of type Area or Page).
  99:                if (!isVisible && type != NodeTypes.Area && type != NodeTypes.Page)
 100:                    continue;
 101:  
 102:                // Finally, can add the node to the collection.
 103:                SPNavigationNode node = SPNavigationSiteMapNode.CreateSPNavigationNode(
 104:                    title, url, type, existingNodes);
 105:  
 106:  
 107:                // Now we need to set all the other properties
 108:  
 109:                // If we didn't have a CreatedDate or LastModifiedDate then set them to now.
 110:                if (node.Properties["CreatedDate"] == null)
 111:                    node.Properties["CreatedDate"] = DateTime.Now;
 112:                if (node.Properties["LastModifiedDate"] == null)
 113:                    node.Properties["LastModifiedDate"] = DateTime.Now;
 114:  
 115:                // Save our changes to the node.
 116:                node.Update();
 117:                node.MoveToLast(existingNodes); // Should already be at the end but I prefer to make sure :)
 118:  
 119:            }
 120:  
 121:        }
 122:    }


Conclusion

Setting up navigation while provisioning the site in code can be hard. Unfortunately it’s not that easy as the AreaNavigationSettings page (in the screenshot) makes you believe it is.

Took me quite a while to get it working but thanks to guys like Gary I’ve managed it..If you read his comments in the code you can see it was quite the challenge to get this thing right. So thanks again mate! :)

Discussions *BETA* Central

Right! Next to the Blogs Central product (demo at http://demo.zevenseas.com btw), we now also have Discussion Central.. which is my little baby ;)

So, what does it do? The primary function of it is to aggregate discussions from discussion lists throughout all the WebApplications that are associated to the same SSP. And an example of such an aggregation looks like this:

discussionoverview

You may have noticed that it looks a lot like the Live Feed page from Facebook.. and yes.. you are correct! Facebook was my inspiration (quite literally :)

We also added the ViewTracking mechanism, this piece of functionality comes from Blog Central. By adding this type of functionality we can quickly see which discussions are viewed most and thus we can sort on that. Basically the same as any other Web2.0 aggregation page where you can sort on Most Replies/Most Viewed.

Another, more abstract, view of those discussions is the following :

discussionstyle2

So.. let me know your thoughts on this one.. you can play with it yourself real soon on http://demo.zevenseas.com  :)

IGNITE recap

After a pretty exhausting but very interesting week I can say that SharePoint 2010 will be very.. awesome..  (that was pretty much THE word of the week by a particular trainer and a few attendees (amongst them were SharePoint heroes like Tobias Zimmergren, Waldek Mastykarz, Joris Poelmans (AKA JOPX)))

After seeing a lot of sessions in Vegas at the SPC09, I thought that I had seen all the cool new things that are coming but this week showed a couple more.

One of the biggest new things for me was the removal of .stp files and instead of those, now we have .wsp’s that are called “WebTemplates”. Because they are .wsp’s, we can make use of the upgrade functionality. Meaning that in 2010 we have UPGRADEABLE webtemplates!!

Once more..

in 2010 we have UPGRADEABLE webtemplates!!!

To give you the bigger picture ..

  1. User can click together the layout..
  2. User can save the site as template
  3. Developer can import the WSP into VS
  4. Developer can upload the WSP as a farm solution
  5. Sites can be created based on that custom webtemplate
    1. Developer modifies the webtemplate according to new business needs
    2. Developer updated WSP
    3. WSP get’s upgraded
    4. Existing sites get updated using the Feature Update framework

(at least.. that’s the story ;))

Can’t believe they didn’t shout this one out as big as the ‘F5 experience’ for example. I mean.. businesses were (and are) waiting for many years to have this functionality available..

For now I just wanted to say.. thanks Microsoft for making this possible, thanks Wouter van Vugt, Vesa Juvonen and Todd Carter for giving an awesome developer training and thanks Dan for giving me his seat ;)

Quick update! ;)

Yesterday was the last day of a big project.. was a good one where I’ve build something amazing stuff but now it’s time for something else..

There seems to be time left the coming weeks to pick up some smaller projects (or stuff for TunnelPoint/ProduShare/Blog Central) but it could be nice to pickup some other stuff that is available and if anyone has an interesting project lying around (and wants me in the team) please don't hesitate to contact me on robin at zevenseas.com or send an email to hans at zevenseas.com.

On another note..  Vegas is coming up! Will be very good with all the SharePoint peeps around.. after Seattle and London I’m really looking forward to this conference! One big happy family :)

 

Ill_be_at_SPC[2]

Building a custom Nintex Workflow Activity : using the SitePicker

Yes yes.. another post on how to re-use the webcontrols of Nintex in your own custom workflow activity.. this time it’s the SitePicker. Which looks like this:

sitepicker

This picker thing took me the longest time to get working since it requires (which I’m not really sure of.. just was glad that I have it working :)) a LOT of javascript. First I added this chunk of javascript for the initialization of the picker:

var curSelObjID = "";
var curSelObjIOrigDBColor = "";
var webUrl = "";
var webID = "";
var folderID = "";
var folderUrl = "";
var siteID = "";
var isFormLib = false;
function SitePickerHandleOnClick(anchorid, type, url, webid, siteid, folderid) {
    var anchorItem = document.getElementById(anchorid);
    if (anchorItem != null) {
        if (curSelObjID != "") {
            var curAnchorItem = document.getElementById(curSelObjID);
            curAnchorItem.style.backgroundColor = curSelObjIOrigDBColor
        }
        curSelObjID = anchorid;
        curSelObjIOrigDBColor = anchorItem.style.backgroundColor;
        webUrl = url;
        webID = webid;
        siteID = siteid;
        folderID = folderid;
        //anchorItem.style.backgroundColor = "#EB501C"; // dark Nintex color
        anchorItem.style.backgroundColor = "#F39B23"; // light Nintex color
    }
}
function SitePickerNeedToExpandHandler(url, webid, siteid, folderid) {
    if (webUrl == "" && webID.length > 0) {
        webUrl = SitePickerGetWebURLFromGUID(siteID, webID);
        //webUrl = WebIDUrl(webID);
    }
    if (folderUrl == "" && folderID.length) {
        folderUrl = SitePickerGetFileURLFromGUID(siteID, webID, folderID);
    }
    if ((webUrl.substring(0, url.length) == url) || (folderUrl.substring(0, url.length) == url))
        return true;
    return false;
}
function SitePickerPostInit() {
    if (curSelObjID != "") {
        var selObj = document.getElementById(curSelObjID);
        if (selObj != null) {
            //selObj.parentElement.focus();
            //selObj.focus();
        }
    }
}
function GetSitePickerListBGColorHandler(anchorid, url, webid, siteid, folderid) {
    if (webUrl == "" && webID.length > 0) {
        webUrl = SitePickerGetWebURLFromGUID(siteID, webID);
        //webUrl = WebIDUrl(webID);
    }
    if (folderUrl == "") {
        if (siteID != "" && webID != "" && folderID != "")
            folderUrl = SitePickerGetFileURLFromGUID(siteID, webID, folderID);
    }
    if (url == folderUrl) {
        curSelObjID = anchorid;
        curSelObjIOrigDBColor = ""; // default color
        return "#F39B23";
    }
    else
        return "#000000";
}
function GetSitePickerWebBGColorHandler(anchorid, url, webid, siteid, folderid) {
    if (webUrl == "" && webID.length > 0) {
        webUrl = SitePickerGetWebURLFromGUID(siteID, webID);
        //webUrl = WebIDUrl(webID);
    }
    if (url == webUrl && folderID == folderid) {
        curSelObjID = anchorid;
        curSelObjIOrigDBColor = ""; // default color
        return "#F39B23";
    }
    else
        return "#000000";
}

Then to get the value of the sitepicker, this bit of javascript has to be inserted into the TPARetrieveConfig method:

function TPARetrieveConfig() {
    SetFilter(true, true, true, true);
    SetAllowSelectWebs(false);
    DoInternalOnLoad('SitePicker', webUrl, webUrl + "/_vti_bin/NintexWorkflow/Workflow.asmx", true);
    webID = configXml.selectSingleNode("//Parameters/Parameter[@Name='WebId']/PrimitiveValue/@Value").text;
    folderID = configXml.selectSingleNode("//Parameters/Parameter[@Name='FolderId']/PrimitiveValue/@Value").text;
    siteID = configXml.selectSingleNode("//Parameters/Parameter[@Name='SiteId']/PrimitiveValue/@Value").text;
    if (configXml.selectSingleNode("//Parameters/Parameter[@Name='Url']") && configXml.selectSingleNode("//Parameters/Parameter[@Name='Url']/PrimitiveValue/@Value").text != "") {
        translateTextAndInsertIntoRefTextField(parentUrl, configXml.selectSingleNode("//Parameters/Parameter[@Name='Url']/PrimitiveValue/@Value").text);
        document.getElementById(rdoEnterUrl).checked = true;
        document.getElementById(rdoChooseSite).checked = false;
        document.getElementById("SitePicker").style.display = "none";
        document.getElementById("enterUrl").style.display = "block";
    }
    else {
        document.getElementById(rdoEnterUrl).checked = false;
        document.getElementById(rdoChooseSite).checked = true;
        document.getElementById("SitePicker").style.display = "block";
        document.getElementById("enterUrl").style.display = "none";

 

}

 

    SetFilter(true, true, true, true);
    SetAllowSelectWebs(false);
    DoInternalOnLoad('SitePicker', webUrl, webUrl + "/_vti_bin/NintexWorkflow/Workflow.asmx", true);
}

Then to write the values back, this bit of javascript is being used in the TPAWriteConfig method:

function TPAWriteConfig() {
    configXml.selectSingleNode("//Parameters/Parameter[@Name='WebId']/PrimitiveValue/@Value").text = self.webID;
    configXml.selectSingleNode("//Parameters/Parameter[@Name='FolderId']/PrimitiveValue/@Value").text = self.folderID;
    configXml.selectSingleNode("//Parameters/Parameter[@Name='SiteId']/PrimitiveValue/@Value").text = self.siteID;
    EnsurePrimitiveValueNode(configXml, "Url");
    if (document.getElementById(rdoEnterUrl).checked) {
        configXml.selectSingleNode("//Parameters/Parameter[@Name='Url']/PrimitiveValue/@Value").text = getStringFromRefTextField(parentUrl);
    }
    else {
        configXml.selectSingleNode("//Parameters/Parameter[@Name='Url']/PrimitiveValue/@Value").text = "";
    }
    
    return true;
}

And to make sure the SitePicker is loaded, this bit has to be referenced:

<script src="/_layouts/NintexWorkflow/SitePicker.js?Version=<%=Nintex.Workflow.Licensing.License.VersionInfo %>" type="text/javascript" language="javascript"></script>

You can see in the variables there are two ways to store the selected List (or web/site/folder) namely:

  • Option 1:
    • ListUrl
  • Option 2:
    • SiteId
    • WebId
    • FolderId

In the codebehind we can use the following piece of code to get to the desired selected location:

 

Guid SiteGuid = this.SiteId;
Guid WebGuid = this.WebId;
Guid ListGuid = this.FolderId;
                
if (this.SiteId == Guid.Empty && (!string.IsNullOrEmpty(this.Url)))
{
    Utility.GetIdsFromSharePointUrl(this.Url, out SiteGuid, out WebGuid, out ListGuid);
}

So it doesn’t matter what path is chosen, in both ways we get all the GUID’s we want to navigate to the desired location by making use of the Utility Class that is supplied with the Nintex.Workflow.dll ;)

 

Technorati Tags: ,,

Building a custom Nintex Workflow Activity : using the CredentialPicker

In my previous post I mentioned that I also wanted to use the CredentialPicker from Nintex to include in my own custom activity and since of this week I finally managed to achieve this! ;)

What is the CredentialPicker? This picker allows you to set an username and password combination so that an activity can be ran using those credentials. But you can also use a lookup to a workflow constant credential that can be defined on web / site / web application level. So it’s like the SPSecurity.RunWithElevatedPriviliges method but then in a workflow activity. So I think you can see the potential of this control.. In an activity it looks like this :

credentialpicker

Doesn’t look that spectacular eh? But.. it’s very powerful.. very.. 

So how do we get this awesome little control in our dialog page?

  1. Add the UserControl declarative in the header of the page
    <%@ Register TagPrefix="Nintex" TagName="CredentialControl" Src="~/_layouts/NintexWorkflow/CredentialControl.ascx" %>
  2. Add the javascript code to retrieve the current set values using the TPARetrieveConfig method
    function TPARetrieveConfig() {           
    
        if (configXml.selectSingleNode("/NWActionConfig/Parameters/Parameter[@Name='Username']") && configXml.selectSingleNode("/NWActionConfig/Parameters/Parameter[@Name='Password']")) {
    
            cc_setUsername("<%= credentialPicker.ClientID %>", configXml.selectSingleNode("/NWActionConfig/Parameters/Parameter[@Name='Username']/PrimitiveValue/@Value").text);
    
            cc_setPassword("<%= credentialPicker.ClientID %>", configXml.selectSingleNode("/NWActionConfig/Parameters/Parameter[@Name='Password']/PrimitiveValue/@Value").text);
    
        }
    
    }
  3. Add the javacsript to write the current value set using the TPAWriteConfig method
    function TPAWriteConfig() {          
    
        EnsurePrimitiveValueNode(configXml, "Username");
    
        EnsurePrimitiveValueNode(configXml, "Password");
    
        configXml.selectSingleNode("/NWActionConfig/Parameters/Parameter[@Name='Username']/PrimitiveValue/@Value").text = cc_getUsername("<%= credentialPicker.ClientID %>");
    
        configXml.selectSingleNode("/NWActionConfig/Parameters/Parameter[@Name='Password']/PrimitiveValue/@Value").text = cc_getPassword("<%= credentialPicker.ClientID %>");
    
        return true;
    
    }
  4. And then we add the UserControl in the ContentPlaceHolder
     <Nintex:CredentialControl RequiredField="true" DisplayMode="dialog" CssClass="ms-input"
    
            Width="170px" runat="server" id="credentialPicker">
    
        </Nintex:CredentialControl>
  5. To get the credentials in codebehind in the CodeActivity use this
  6. string runtimeUsername = string.Empty;
    
    string runtimePassword = string.Empty;
    
    CredentialValue.DetermineRuntimeCredentials(
    
    this.Username, //UserName Property
    
    this.Password,  //Password Property
    
    out runtimeUsername, 
    
    out runtimePassword, 
    
    ctx.Web.ID, 
    
    ctx.Web.Site.ID);
    
    NetworkCredential credentials = null;
    
    if (runtimeUsername.Contains(@"\"))
    
    {
    
       string[] strArray = 
    
            runtimeUsername.Split(new char[] { '\\' });
    
       credentials = 
    
            new NetworkCredential(strArray[1], runtimePassword, strArray[0]);
    
    }
    
    else
    
    {
    
       credentials = new NetworkCredential(runtimeUsername, runtimePassword);
    
    }
 
Technorati Tags: ,,

 Next >>

 
 
 

© 2009 Community Kit For SharePoint