How to properly hide ContentPlaceHolders in your SharePoint 2010 Master Page

Recently I had a friend ask me to help him with an issue on a page layout they were having.  When he opened the page in SharePoint designer and went to edit the page layout, he saw this message.

The first thing I did was have him search the master page for TitleInTitleArea, since that did not show any results I assumed the ContentPlaceHolder was missing.

I had him add an ASP:Panel to the bottom of his master page and add the missing ContentPlaceHolder there.

    
ContentPlaceHolder id="PlaceHolderPageTitleInTitleArea" runat="server" Visible="false" />

Once that was done he no longer had the error on his PageLayout and the issue was fixed.

I quickly received another ping. His page was now broken.

I knew from this error that there were duplicate place holders on his page, so I had him go back and remove the placeholder we just added and recheck his page layout.  His page layout was still showing the same error.

Once we started a sharing session and I was able to view his master page and found the issue.

The person who created the master page had commented out the placeholders.

Once the ContentPLaceHolders that were commented out were moved into an ASP:Panel that was hidden the page layout was no longer broken and there were no more errors.

Lesson: Don’t comment out your ContentPlaceHolder. Move the ones you are not going to use into an ASP:Panel with the visibility set to false.

Here is a screen shot of my asp:panel on a recent custom master page.

Update Note: There is a ContentPlaceHolder that you do not want to add to the hidden panel. Please read this post.

How to Troubleshoot JavaScript inside SP2013 apps

aclark

The problem:

Remember the good old days? Who cares about deployment standards, let’s just fire up SharePoint Designer to find our custom JavaScript file inside our SharePoint site to make edits. Once the edits are made, click save and refresh the webpage to view the alterations.  Rinse and repeat the process until your JavaScript is perfect.

The above process to alter JavaScript after deployment is not possible with the new app model inside SharePoint 2013. Go ahead and try to connect to the URL of a recently deployed app using SharePoint Designer 2013, I will wait here for you. As the author of a SharePoint Hosted application, it is a breath of fresh air that once my app is installed that no one can fiddle with it. No more emails or phone calls from ‘power users’ that altered my JavaScript only to break the functionality of the entire page.

An unfortunate side effect to this change in architecture means that it makes it somewhat more difficult for developers to troubleshoot JavaScript bugs after deployment since SPD 2013 is no longer an approach. From this point further, we have to rely on the developer tools provided inside browsers.  The options that we have are:

  • F12 Developer Tools inside Internet Explorer
  • FireBug with FireFox
  • Developer Tools plugin with Chrome

 

For the seasoned scripting developers, the process of troubleshooting scripts is old news to you. However for those that are new to the scene, the following steps will acclimate you to using these free browser tools. For this article, I chose Chrome because for developing inside O365 Developer Preview it is clearly the fastest and responsive browser out there. During my development period, Firefox was slow as molasses for me and IE was faster but just plain weird with random frozen screens. The dev preview site is in beta and still was so I am positive that IE will outperform in the near future.

With the flaming torches and pitchforks thrown to the side, let’s walk through the process of troubleshooting JavaScript for newbies.

The Solution: 

Click cntrl+shift+J to pull up the console inside Chrome Developer tools. This console will allow you to run JavaScript commands on the window that you are currently viewing. This approach works fine for moving controls around or injecting custom styles which is very similar to using jsfiddle. However the wheels start to fall off the wagon when inspecting various ‘sharepointy’ variables.  For example, running any type of command will spit back a ‘ReferenceError’. 

In order to play with SharePoint, you will need to put a break point inside your client side code that will pause loading of the page.  Click on sources to find your custom client side code and place a breakpoint after the variable has been instantiated. In the example below, the variable is available after line 71.

With the breakpoint set and going back to the console inside Chrome, I start to get better intellisense:

With the breakpoint set, I can finally get at my SharePoint object referenced in my code. This is where I fiddle with accessing list level data before putting it inside my code file. In the examples below, I am letting the output tell me what can be accessed and how certain methods return data. The output for the Modified date tells me to do more research on date strings since getDate does not exactly give me what I am looking for.

With the basics covered on debugging, time to get back to your code. There are plenty of samples out there to get the creative process started: How to: Complete basic operations using JavaScript library code in SharePoint 2013 (http://msdn.microsoft.com/en-us/library/jj163201(v=office.15).aspx) To continue with the deep dive with JavaScript, follow the ‘JavaScript for the C# Developer’ with Doug Ware. (http://www.elumenotion.com/Blog/Lists/Posts/Post.aspx?ID=160)

 

Customizing the search box in SharePoint 2010

In this blog post I will show you how to customize the search area in the header of your custom master page.

Since this site is for an intranet, I started by making a copy of the v4.master and renaming that copy. You could also use the Starter Master Page, by Randy Drisgill on CodePlex.

When I customize a master page typically I will wrap the #s4-searcharea in a DIV using my own ID. This ID will only be used for placement and positioning.

#my-searcharea { float: right;  padding-top: 15px;  position: relative; }

Note: Depending on your layout, your CSS may look a little different. 

Next we want to add some CSS to make our search area, look pretty/cool/better than OOTB SharePoint. Here are some examples of what we have done in the past.

#my-searcharea #s4-searcharea #SRSB {
background: url(“../images/search.png”) no-repeat scroll 0 0 transparent;
height: 30px;  width: 230px;}

Note: your height and width would change according to your image.

If I didn’t include the #my-searcharea before the other two ID’s then my pretty search box would show on the search results page. The #s4-searcharea is also used on the search results page, just above the content area.

Q: Why not just change the #s4-searcharea that is already in place?

A: Two reasons – 1) since I am positioning my search area within my header, I don’t want that CSS to carry over to my search results page, and 2) I don’t think it’s a good idea to alter the #s4-search area CSS as it could be used in a number of different places. Remember that we are only focusing on the search box in the header area.

The CSS above just placed and image behind the DIV tag. We have a bit more styling to do before we have finished our task.

Note: The tool I like to use most for these next tasks is FireBug. I love that I can quickly copy the CSS from within FireBug from the corev4.css and paste it directly into my custom.css file.  The other great thing, you can make changes in the CSS with FireBug to see what your final code might look like.

Using FireBug I highlight the <input> tag for the search box and copy the CSS into my custom style sheet.

.s4-search input.ms-sbplain {
background: url(“/_layouts/images/bgximg.png”) repeat-x scroll 0 -511px #FFFFFF;
border: 1px solid #E3E3E3 !important;
font-size: 1.1em;
height: 17px;
padding: 2px 3px 0;
width: 191px !important;}

I make my CSS changes removing redundant CSS code. This code will still be called in the corev4.css sheet. No need to bloat my CSS file!

#my-searcharea .s4-search input.ms-sbplain {
background-image: none;
background-color: transparent
border: 0px !important; /* the original code had !important so I need to use it here too!*/
font: normal 12px Arial, Helvetica, sans-serif;
padding: 5px 0px 5px 5px; }

Next we want to remove the search icon. Using FireBug again I locate the tag where I need to use some CSS magic. The image is in a link, so we just want to hide the image.

#my-searcharea .ms-sbgo a img {display: none;}

That looks like I’m finished but we are not quite there. Try to hover over the search icon and there is nothing to click! We need to add another line of CSS so that we can click the search icon.

#my-searcharea .ms-sbgo a {display: block; width: 25px; height: 25px;}

When I use FireBug again, I can see the outline if my link, it looks like it covered the whole icon.

The last part that I want to remove the italic font style in the search box.

#my-searcharea input.s4-searchbox-QueryPrompt {font-style: normal; }

I also elected to use a different font and color in the input box,  I made those changes to the class #my-searcharea .s4-search input.ms-sbplain { .

Here’s the final result.

Thanks for reading!

Before you cram in that javaScript

aclark

2002 was a great year……

MJ was still in the league, Phil Jackson wrapped up his third three-peat with the Lakers and the playoffs were entertaining. Who doesn’t remember a dominant and relevant Shaq referring to the Kings as the Sacramento ‘Queens’ and being entertained with another game seven in the Western Conference Finals.

Technology was no stranger to controversy as blogs and books were being released regarding web performance tuning tips.  Some authors even went so far to suggest excluding or minimizing the use of JavaScript and style sheets.  Published in 2002….”There are some nice features to both JavaScript and style sheets, but at a big cost. Life is better without them.” Top Ten Web Performance Tuning Tips http://www.oreillynet.com/pub/a/javascript/2002/06/27/web_tuning.html

Combining the high cost of hardware with the somewhat slow speeds of internet access, developers in the early 2000s had to be aware of how long their web pages would render for their visitors. The performance concerns that developers had back then are still relevant today.

Technology and connectivity might be considered leaps and bounds advanced from the period mentioned earlier, but visitors are requesting information using multiple devices, including cellphones with spotty reception and tablets using shared slow connection at a coffee shop. You have to be aware of how ‘heavy’ your pages are and how many resources are needed to display your pages. There are several tactics to improve performance of web sites and pages, but let’s concentrate on the inclusion of JavaScript in pages and more importantly how they are included inside SharePoint.

For the past year or so, the hottest trend with SharePoint is to include a personal favorite JavaScript library in SharePoint. Most actions inside SharePoint involve a page load which typically translates to a physical screen flicker to your visitors. In an effort to make pages reflect a more modern feel, developers have been using JavaScript to dynamically alter and add data to a page without posting the page back to the server. Developers can either write their own script or include a framework that encapsulates common functions. One example of a framework that is unique to SharePoint is SPServices.  SPServices has exploded with popularity and has been downloaded over 61,000 times.  Outside of SharePoint, jQuery is extremely popular with developers to ‘simplify the client-side scripting of HTML’.” jQuery tools” is another open source framework that is built using the jQuery library to supply even more client side functionality. Combined together, these frameworks are just a few examples that have been used to unlock SharePoint from the client side.

There are a few options to include scripting into sites:

  • Alter the Master Page to include JavaScript
  • Create or Alter a Page Layout using Visual Studio or SharePoint Designer (SPD)
  • Use Content Editor Web Parts to include JavaScript

 

To complicate this further, there are different techniques for including JavaScript:

  • Inline scripting injected inside a script tag
  • Reference to a script file inside your site
  • Reference to a Content Delivery Network (CDN)

 

Using JavaScript in your Custom Master Page

It is common to make a JavaScript reference inside the master page used by your SharePoint site.  The image below shows three script files are being included inside the head tag of a master page.

Positive:

The benefit of this approach is that now the scripts will be available to any resource that uses the master page. As opposed to altering numerous pages to include a script file, you now have to make one entry in the master page.

Negative:

When visiting Alaska, there is no need to pack that surf board. If scripting is used for one webpart that is  needed on only one page, then it is unnecessary to have this script load for every other page inside your site. Including the script on the master page will ensure that the file is loaded into the browser whether or not the scripting is actually used.

Using JavaScript in your Page Layouts

To alleviate the issue of loading only necessary components, page layouts are used to reference scripting when a specific page type is loaded by a visitor. An easy approach to this is to create a new page layout using SharePoint Designer 2010 and include your script inside a content region with an ID of PlaceHolderAdditionalPageHead.

Positive:

Using JavaScript page layouts ensures that the scripts are called only when a specific page is loaded by your visitors. With this method the pages that do not use this page payout should weigh less. As an added bonus, developers can skip using SharePoint Designer and utilize Visual Studio 2010 to create page layouts. Using Visual Studio 2010 gives you the flexibility to deploy page layouts as a feature as opposed to manual edits inside SharePoint Designer 2010. To learn more about this technique visit the follow blog: “Every Problem has a solution, Even SharePoint Branding.” (http://www.sharepointcat.com/2011/08/every-problem-has-a-solution-even-sharepoint-branding/)

Negative:

Implementing page layouts implies a baseline knowledge of content types and planning as to where or what types of pages are needed within your site. Perhaps that should not be considered a negative when in essence it forces you to slow down. For all the copy and paste coders out there, it is assumed that you have some HTML knowledge for inclusion of your JavaScript.

Using JavaScript in a CEWP

Saving the best for last? The last option for including script inside SharePoint involves using a Content Editor Web Part (CEWP) to link to a text file that contains your custom script.

Positive:

None.  This abomination of an approach essentially does the same as using a page layout by ensuring that the script is only loaded on a specific page.

Negative:

By not paying attention to permissions or communication, an unknowing page editor could delete this web part from the SharePoint page which could then cripple the entire page. Perhaps this scenario is unlikely for the masses but it is fair to say that using CEWP is not even close to being robust as page layouts. When new pages are created, the creator can select your custom page layout that includes custom scripting. I would much rather have my scripts propagated inside a reusable container as opposed to manual entries to individual pages.

JavaScript Techniques

     Inline script

Inline scripting means inserting your JavaScript inside a script tag. Using this approach means that you will have to update whatever mechanism was used to introduce the script whether it be the master page or page layout.  Having to update the entire master page just to make a scripting change seems like over kill.

     Script Files

Using files that contain custom script provides another layer of flexibility. This enables developers the ability to alter the script directly as opposed to editing master pages or page layouts. Putting the files in a location that developers can access without relying on SharePoint Designer 2010 could also be viewed as a win especially in the scenarios where access to SharePoint Designer is locked down.

There are two types of methods to include JavaScript files with the script tag or with a SharePoint ScriptLink control. The old method uses the script tag with new approach using the SharePoint ScriptLink control.

<script src=”/Style Library/custom/jquery-1.4.4.min.js” type=”text/javascript”></script>

<SharePoint:ScriptLink ID=”ScriptLink1″ Name=”~sitecollection/Style Library/custom/JS/jquery-1.4.4.min.js” runat=”server” />

MSDN: ScriptLink Class http://msdn.microsoft.com/en-us/library/microsoft.sharepoint.webcontrols.scriptlink.aspx

     Content Delivery Network (CDN)

Inside the script tag, instead of referencing a relative path to an internal resource you can point to a publicly accessible file hosted on a Content Delivery Network (CDN), for example: http://ajax.aspnetcdn.com/ajax/jQuery/jquery-1.8.2.js.  The benefit of this approach is that it will help out with performance. In regards to global visitors, using a CDN will dynamically determine which hosting server is closest to the request and serve content accordingly. Pay attention to this especially when thinking of Asia or Europe visitors who would normally have to download resources from US based servers. The glaring downfall to using a CDN is that it could be considered malicious to some corporate networks that could have this traffic blocked by their firewall.

Conclusion

There are several options for including custom scripts inside your SharePoint farm. Your decision will impact how quickly content is rendered to visitors.  It is up to you to make a qualified decision as to which approach fits your corporate identity. Do you have development resources? Is this for a Proof of Concept site? Do security restrictions limit access to external sources? This blog post should outline what options are available to you with additional resources provided below.

Extra Credit Reading

When working with JavaScript files, you probably have wondered why there are full versions and minified versions of the same JavaScript file. This is another technique to help out with performance by essentially shrinking the physical size of the files. The smaller the JavaScript file is…the quicker the download is on the browser for your visitors.  Paul Schaeflein has a great write up on this process in his blog: Minifying JavaScript Files with Build Events (http://www.schaeflein.net/Pages/Minifying-JavaScript-Files-with-Build-Events.aspx)

 

Lastly there is a CodePlex solution worth evaluating called SP SIN (http://spsin.codeplex.com/). This allows your SharePoint site to load in both CSS and JavaScript files based on the inclusion of words in the URL. There are several benefits to using this approach since it allows alterations without having to edit any pages or master pages. In my opinion it takes the benefits that you would get by using separate page layouts but centralizes the management of resources inside one SharePoint List.

 

References

Creating a Page Layout in SharePoint 2010 using Visual Studio 2010 (http://blog.beckybertram.com/Lists/Posts/Post.aspx?ID=71)

Exploring the Power of Page Layouts in SharePoint 2010 WCM Sites (http://channel9.msdn.com/Events/TechEd/Europe/2012/OSP335)

Page Layouts in SharePoint (http://blogs.msdn.com/b/kaevans/archive/2011/04/02/page-layouts-in-sharepoint.aspx)

jQuery: ‘jQuery is a fast and concise JavaScript Library that simplifies HTML document traversing, event handling, animating, and Ajax interactions for rapid web development. jQuery is designed to change the way that you write JavaScript.’  http://jquery.com/

jQuery Tools: ‘The missing UI library for the Web. jQuery Tools is a collection of the most important user-interface components for modern websites. ‘  http://jquerytools.org/

SharePoint Drag/Drop file upload using the ASP.NET AJAX Control Toolkit

In my current work on a custom interface for a document management system, I was challenged to create a drag/drop interface for adding files to SharePoint. 

I investigated a number of alternatives. Initially these were my considerations:

  • Not all browsers (most notably IE9) do not support HTML5, which natively supports drag/drop.  
  • Even if HTML5 is supported, there’s still quite a bit of wiring to do in Javascript. 
  • As developers, we try not to recreate the wheel.  If a problem has already been solved, it’s usually a better alternative to use that – at least as a starting point.

As it turns out, there’s no shortage of drag/drop solutions out there.  But try one that applies to SharePoint, provides compatibility with non HTML5 browsers, shows a progress bar, etc.   In the end I decided to try the ASP.NET AJAX Control Toolkit.

Getting started

On the surface, installation is straightforward for anyone who is familiar with ASP.NET development.  Add an entry to the web.config, drop the appropriate DLL in the GAC, and that’s pretty much it.  However, (ahem) we’re using SharePoint here, which brings up a couple of issues that we’ll need to address.   Fortunately I’ve already hammered out these issues, so you don’t have to.

Issue 1:  Version

We need to use the .NET 3.5 version.   There are two compiled versions.  We are again reminded that SharePoint 2010 doesn’t use the latest version of .NET.  

Issue 2: ScriptManager

The ScriptManager packaged with the Toolkit needs to be used, INSTEAD of the standard ASP ScriptManager which is on all master pages in SharePoint.

before:

[xml]

<asp:ScriptManager id="ScriptManager" runat="server" …." />

[/xml]

after:

[xml]

<%@ Register Assembly="AjaxControlToolkit, Version=3.5.60501.0, Culture=neutral, PublicKeyToken=28f01b0e84b6d53e" Namespace="AjaxControlToolkit" TagPrefix="ajaxToolkit" %>

<ajaxToolkit:ToolkitScriptManager runat="server" …. />

[/xml]

Issue 3: File Uploader is not ready for prime time

The drag/drop control is called AjaxFileUpload (not to be confused with AsyncFileUpload, which is also part of the toolkit).   Once you have the ScriptManager issue handles, you’ll be able to get things working using the simple demo.  However, I found (as of the 5/1/12 release) that there were a couple of bugs.

1. The control assumes that no parameters are present on the page which contains the control.  This is documented in this bug report.  I won’t go into detail on this.  Suffice it to say that it should be fixed in the future.   The impact is that the control cannot be used on most SharePoint pages including dialogs invoked using SP.UI.ModalDialog.showModalDialog() – which appends the parameter IsDlg=1 even if you don’t explicitly do so!

2. a number of features of the drag/drop uploader do not work.  For example, exceptions generated when the code is downloading are not “passed through” to the javascript event which should be fired in the event of an error.   In fact, when I delved into the code, I found that the OnClientError event is never fired!

The way I fixed this issue was to download the AjaxToolkit code and “just fix it”.  I spent a few hours learning how the code works, and modified the code itself, in C# and Javascript.   For anyone interested in following this path, you can download the changed code here (I only included the files I changed).  When you download the code, make sure to use the version targeted to .NET 3.5.  It’s a VS 2008 project, but of course it’s ok for you to convert it to VS 2010.

Finally: Hooking it up to SharePoint

The file uploader control is very clever.  It posts back to the same page it’s located on (this is the ajax part) and calls a code block that you can define using C# in your ASP or Codebehind.   Mine looks something like this:

[csharp]

protected void ajaxUpload1_OnUploadComplete(object sender, AjaxControlToolkit.AjaxFileUploadEventArgs e)
{
        //you’ll need some logic in here to determine where to put the files.
        string filename = string.Format("{0}/{1}", SPContext.Current.Site.Url, e.FileName);

        using (SPWeb web = new SPSite(uploadTarget).OpenWeb())
        {
            web.AllowUnsafeUpdates = true;
            web.Files.Add(filename, e.GetContents(), true);
            web.AllowUnsafeUpdates = false;
        }
}

[/csharp]

From the client interface end of things, you’ll also need to put in code to provide feedback.  There’s a good The code located here. provides a pretty good example of that; here’s another one:

[javascript]

//hook this up to the OnClientUploadError property of the control

function onError(sender, e) {
//this bit of code adds an error message to a designated “errors” area.
var test = document.getElementById("uploadErrors");
test.style.display = ‘block’;
var fileList = document.getElementById("fileList");
var item = document.createElement(‘div’);
item.style.padding = ’4px’;
item.appendChild(createFileInfo(e));
fileList.appendChild(item);
}

function createFileInfo(e) {
var holder = document.createElement(‘div’);
holder.appendChild(document.createTextNode(e.get_fileName() + ‘: ‘ + e.get_errorMessage()));
return holder;
}

//hook this up to the OnClientUploadComplete property of the control

function onClientUploadComplete(sender, e) {
     alert("uploaded");
}

[/javascript]

Using this method, errors are returned to the web user.  Once our designers get through with it, it’s going to be REALLY slick!

Implementing custom folder statistics in SharePoint 2010 using c#

In one scenario this past week, I needed to display the total number of files and folders within any folder.  These numbers needed to be recursive – so if a document is three folders deep within the current folder, that still counts.   Same with folders.  I also needed to show a date representing the modified date of the MOST RECENT item or folder, again recursive to the last level.

I found a way to achieve this using a single CAML query and some fancy XSL parsing!

The folder and document counts would be displayed like this:

image

I’m already using other mechanisms to get lists of folders for display.  The XSL-driven styling shown is probably the topic of a future post.  The challenge was, how to get those counts and dates…

I started with an SPQuery.  The following recursively query pulls the basic information required, within the folder specified.

[csharp]

SPQuery query = new SPQuery();
query.Folder = folder;
query.Query = string.Empty;
query.RowLimit = uint.MaxValue;
query.ViewFields = "<FieldRef Name=’Modified’ Nullable=’True’/><FieldRef Name=’ContentTypeId’ Nullable=’True’/>";
query.ViewFieldsOnly = true;
query.ViewAttributes = "Scope=’RecursiveAll’";
SPListItemCollection items = parentList.GetItems(query);

string itemsXml = items.Xml;

[/csharp]

The trick here is the ViewAttributes property.  There are a few different ways to run an SPQuery, and this was the Scope that gave me the results I needed.  Note that an SPListItemCollection may be accessed as API objects OR XSL, and I chose to pull out my results using XSL.

Our query result is something like this (if you look closely, you’ll see that we have two folders and two documents here):

[xml]

<rs:data ItemCount="4">
  <z:row ows_Modified="2012-05-31 12:34:01" ows_ContentTypeId="0x01200082B0C5829FE047A1BF58F68DA1DAB12500C7BCD99F82ACA340A0131D59CE62371B" ows__ModerationStatus="0" ows__Level="1" ows_ID="1" ows_Created_x0020_Date="1;#2012-05-31 12:34:01" ows_PermMask="0x7fffffffffffffff" ows_FileRef="1;#depts/it/Lists/CTADocuments/mygroup" />
  <z:row ows_Modified="2012-05-31 12:36:51" ows_ContentTypeId="0x01200082B0C5829FE047A1BF58F68DA1DAB12500C7BCD99F82ACA340A0131D59CE62371B" ows__ModerationStatus="0" ows__Level="1" ows_ID="2" ows_Created_x0020_Date="2;#2012-05-31 12:36:51" ows_PermMask="0x7fffffffffffffff" ows_FileRef="2;#depts/it/Lists/CTADocuments/mygroup/another one" />
  <z:row ows_Modified="2012-05-31 17:49:45" ows_ContentTypeId="0x010100EB5D8789C471B04E80E2A7481607C23B" ows__ModerationStatus="0" ows__Level="1" ows_ID="9" ows_Created_x0020_Date="9;#2012-05-31 17:49:45" ows_PermMask="0x7fffffffffffffff" ows_FileRef="9;#depts/it/Lists/CTADocuments/Just_the_Essentials_Publishing.master" />
  <z:row ows_Modified="2012-06-07 17:05:11" ows_ContentTypeId="0x010100EB5D8789C471B04E80E2A7481607C23B" ows__ModerationStatus="0" ows__Level="1" ows_ID="10" ows_Created_x0020_Date="10;#2012-06-07 17:05:11" ows_PermMask="0x7fffffffffffffff" ows_FileRef="10;#depts/it/Lists/CTADocuments/mygroup/another one/junk.txt" />
</rs:data>

[/xml]

In this case it was more straight-forward to take the raw XSL and get what I needed using lamda expressions.  For example, to get document counts I applied an understanding of how content type id’s work.  All document content type id’s which inherit from Document (with id 0×0101), start with that number:

[csharp]

const string docCtID = "0×0101";
const string ctypeIDElement = "ows_ContentTypeId";
documentCount = rowElements
    .Where(dt => dt.Attribute(ctypeIDElement).Value.StartsWith(docCtID))
    .Count();

[/csharp]

Putting it all together

Finally, we can wrap all of this logic into a single, fairly dense method.   And achieve our goal using only one query!

[csharp]

    const string docCtID = "0×0101";
    const string folderCtID = "0×0120";
    const string ctypeIDElement = "ows_ContentTypeId";
    const string modIDElement = "ows_Modified";
    internal static void GetFolderStats(this SPFolder folder, SPList parentList, out string modDate, out int documentCount, out int folderCount)
    {
        SPQuery query = new SPQuery();
        query.Folder = folder;
        query.Query = string.Empty;
        query.RowLimit = uint.MaxValue;
        query.ViewFields = "<FieldRef Name=’Modified’ Nullable=’True’/><FieldRef Name=’ContentTypeId’ Nullable=’True’/>";
        query.ViewFieldsOnly = true;
        query.ViewAttributes = "Scope=’RecursiveAll’";
        SPListItemCollection items = parentList.GetItems(query);

        //get query results and read them as xml.
        XDocument doc;
        using (TextReader tr = new StringReader(items.Xml))
        {
            doc = XDocument.Load(tr);
        }

        var rowElements = doc.Root.Element(XName.Get("data", "urn:schemas-microsoft-com:rowset")).Elements();
        documentCount = rowElements
            .Where(dt => dt.Attribute(ctypeIDElement).Value.StartsWith(docCtID))
            .Count();
        folderCount = rowElements
            .Where(dt => dt.Attribute(ctypeIDElement).Value.StartsWith(folderCtID))
            .Count();

        if (items.Count == 0)
        {
            modDate = folder.Item.Value(MODIFIED);
        }
        else
        {
            var dtAttList = rowElements
                .Attributes()
                .Where(dt => dt.Name == modIDElement)
                .ToList();
            dtAttList.Sort((a, b) => string.Compare(b.Value, a.Value));  //sort on values, most recent at top
            modDate = dtAttList[0].Value;
        }
    }

[/csharp]

Building a SharePoint 2010 WSP Using TeamCity

I’ve been using Continuous Integration for years.  It’s been a part of almost every project I’ve worked on.  Prior to a few months ago, I was a CruiseControl.NET devotee, but recently a few of my colleagues expressed a preference for TeamCity.  I tried it, and now I’m a convert!

However, the Microsoft stack is not set up with CI in mind.  You’ll need to use a few tricks to set up your build on a computer which does not have a full dev environment.  This is particularly true when developing for SharePoint 2010 using Visual Studio 10.

Using TeamCity

Setting up TeamCity is pretty straightforward.  It’s a free product (up to 20 builds), and can be downloaded on the JetBrains web site.  I won’t go into the basics of TeamCity right now. However, once the product is installed, start by setting up a simple project with a version control settings, but no build steps – it simply downloads the code from your repository.

Preparing to use MSBuild

There are quite a few dependencies to satisfy, for a SharePoint build.  You’re using .NET 3.5, but you’ll want to make sure to use MSBuild 4.0 if you’ve been using VS2010. Features like WSP creation are not available in earlier versions.

Setting up dependencies

I used to do this step though trial and error, but recently found a great resource for this: http://msdn.microsoft.com/en-us/library/ff622991.aspx.  Follow the instructions in step 1. (Prepare the Build System).  Obviously we’re not using TFS here, so skip that step. This step outlines the dependencies, and instructs us on which dll’s we need to manually add to the GAC.  There’s a whole list.  The short explanation is that you copy the dll’s from your dev environment, and place them into the GAC the build server.

One “gotcha” here is that that you need to make sure you’re using the correct version of gacutil.exe when adding items to the GAC.  The reason is that .NET 4.0 adds a second GAC(!), so if you get the following message, you’ll know you have this problem:

Failure adding assembly to the cache:   This assembly is built by a runtime newer than the currently loaded runtime and cannot be loaded.

On my machine, the path of the proper version of gacutil.exe was located in

C:\Program Files\Microsoft SDKs\Windows\v7.1\Bin\NETFX 4.0 Tools\gacutil.exe

Make sure you are working from the most recent version of the Microsoft Windows SDK.   The following page should take you there: http://msdn.microsoft.com/en-us/windows/bb980924.aspx

Remember, YMMV here.  If you do not have SharePoint installed on your build machine, you’ll have to add any SharePoint dll’s necessary to build your project as well.  Anything that you miss will be readily apparent in the next step…

Adding your MSBuild step to TeamCity

Go back to the project you set up, and add a Build step.  Select MSBuild from the Dropdown. Your project should look similar to this:

image

Notice the Command Line Parameters setting.  IsPackaging=True causes the build to actually generate WSP’s for any of your projects that are configured to do so.  Without this parameter, a simple build will be performed.

Hope you enjoyed my first post!  Let me know how it goes.

Implementing Favorites in SharePoint 2010

As a SharePoint consultant, I’m often asked to provide features which “should” exist, but Microsoft just doesn’t provide. Often these are features which might be common in the Web 2.0 world, but – well, not here.

In one of my current projects (based on a Publishing Site), the paradigm of a “favorite button” is central to the desired site functionality. Users should be able to “favorite” any document or folder. These documents and folders are visible in a centrally located list, along with metadata items such as Modified Date and Author.

There are many possible ways to implement this, but initially I chose to use SharePoint 2010’s Social Tagging feature as the basic building block. It’s already set up to store link information by user, and integrates with the Keywords area of the Term Store. On the back end, this is the same mechanism used when you click “I like it” on any page.

This article is more concerned with the back end of things – the code listed below can be wrapped in web services, web parts or whatever you like, to provide functionality to the end user.

Tagging items

Social Tags are essentially key/value pairs, with the key being a Uri (e.g. the url of a web page), and the value being a description. In addition to the tag of “I like it”, other tags may be created in the Keywords area of the Term Store, and then used to tag documents. Here’s the code I’m using to tag a document:

[csharp]
///

/// Updates or adds a social tag for this user.
/// User info is derived from context.
/// Tag is added to term store if necessary.
///

public static void UpdateSocialTag(SPSite site, string socialTagName, string title, string url)
{
SPServiceContext context = SPServiceContext.GetContext(site);
SocialTagManager mySocialTagManager = new SocialTagManager(context);
//Retrieve the taxonomy session from the SocialTagManager.
TaxonomySession taxSession = mySocialTagManager.TaxonomySession;
TermStore termStore = taxSession.DefaultKeywordsTermStore;

Term newTerm = termStore.FindOrCreateKeyword(socialTagName);
Uri tagUri = ConvertToUri(site, url);
mySocialTagManager.AddTag(tagUri, newTerm, title);
}
[/csharp]

The reason this method is called “Update” is that if this Uri has already been tagged, that tag will be replaced.

Retrieving a list of favorites

I’ll also want to display my list of favorites. Social tagging does not intrinsically lend itself to pulling out the list of items which have a particular tag, but we can add that capability using the following code:

[csharp]
///

/// Get the items tagged with TermName for this user.
/// If empty, return an empty array
///

internal static SocialTag[] GetUserSocialTags(SPSite site, string termName)
{
List socialTags = new List();

SPServiceContext serviceContext = SPServiceContext.GetContext(site);
UserProfileManager mngr = new UserProfileManager(serviceContext); // load the UserProfileManager
UserProfile currentProfile = mngr.GetUserProfile(false);// Get the user’s profile

if (currentProfile == null) return socialTags.ToArray(); // user must have profile
SocialTagManager smngr = new SocialTagManager(serviceContext);

// Get the SocialTerm corresponding to this term.
SocialTerm favTerm = GetSocialTerm(termName, currentProfile, smngr);
if (favTerm == null) return socialTags.ToArray();

// Get the terms for the user. Loop through them for conformity.
SocialTag[] tags = smngr.GetTags(currentProfile);
foreach (SocialTag tag in tags)
if (tag.Term == favTerm.Term)
socialTags.Add(tag);
return socialTags.ToArray();
}

///

/// retrieve a named social term.
///

private static SocialTerm GetSocialTerm(string tag, UserProfile currentProfile, SocialTagManager smngr)
{
// Get the terms for the user
SocialTerm[] terms = smngr.GetTerms(currentProfile);
SocialTerm favTerm = null;

//Iterate through the terms and search for the passed tag
foreach (SocialTerm t in terms)
{
if (string.Compare(t.Term.Name, tag, true) == 0)
{
favTerm = t;
break;
}
}
return favTerm;
}
[/csharp]

This code forms the “core” of my favorites system. The ability to tag a document (or remove tag) is wrapped in a web service to allow us to provide provide AJAX functionality. I wrote a web part to display the favorites, with simple sorting and filtering.

Metadata features

One missing element is the metadata, a part of the requirement I mentioned above. For this, I wrote code (as part of my Favorites Web Part) to pull out the necessary metadata for each Uri given, provided it’s a reference to the current site.

Using the .s4-titlerowhidetitle in your custom master page.

When creating a custom master page you want to make sure to keep the s4-titlerowhidetitle class.  If you don’t have this in your custom master page you can find the tag  directly after the #s4-bodyContainer in your v4.master. (Please don’t edit the v4.master directly!)

<div  id="s4-titlerow" class="s4-notdlg s4-titlerowhidetitle"> 
...
</div>
 

IMHO it’s a gem when editing your SharePoint page. When you edit your non-branded SharePoint page ever notice how the header area disappears, that is the .s4-titlerowhidetitle at work.  I definitely want to keep this functionality in my custom master page.

For my custom master page I placed the div tag around everything in my header (logo, search, top navigation, title area, breadcrumb, and status bar container).

5-10-2012 9-50-59 AM

5-10-2012 9-39-02 AM

Now when I edit my page everything in my header is neatly tucked away, and I don’t have to scroll down to see my main content.

image

Thanks for reading!

A cleaner layout when using the Web Part Tool Pane!

How many times have you gone to edit a web part on the page, only to have to scroll to the right to see the tool pane?

5-10-2012 7-57-25 AM

If you happen to have a large screen then this is not much of an issue, but if you have a smaller screen or have numerous windows open it can become a pain.

Here is a great workaround I have come up with that solved my problem.

Move the MSO_Content Div Tag

First in your custom master page, you want to locate the div tag <div id=”MSO_ContentDiv” runat=”server”> (for more clarification on this div tag I suggest reading this post by Waldek Mastykarz). 

I want to  wrap the content that holds the left nav and the main content with this div tag. For this example I added the div tag directly before the  <div id=”s4-mainarea” class=”s4-pr s4-widecontentarea”>. 

<div id="MSO_ContentDiv" runat="server">
<div id="s4-mainarea" class="s4-pr s4-widecontentarea">
....
</div><!-- end #s4-mainarea-->
</div><!-- end#MSO_ContentDiv—>


 

Update your custom CSS file

Next add the following CSS to your page layout or to your Custom CSS file.

#MSOTlPn_WebPartPageDiv #s4-leftpanel {display: none;}
#MSOTlPn_WebPartPageDiv div#MSO_ContentTable {margin: 0px; !important;}

 

A cleaner layout

When in normal edit mode your page looks like this.

5-10-2012 8-16-09 AM

When editing a web part and the tool pane is needed your page will look like this:

5-10-2012 8-25-15 AM

As you can see your left navigation is hidden and your content area has been moved over to the left. You could take this further with your page layouts and un-float specific elements so that they fall in line on the page for easier editing.

Note: If you have web parts in your left hand column that need editing this is not the solution for you.

Thanks for reading!

Subscribe and Follow

Sign up for new posts to be sent to your email.

Archives