Empty tooltip in refinement panel
Sometimes when hovering over a fieldvalue in the refinementpanel the tooltip displays only ‘Refine By:’ without displaying any value.

While another displays an actual value:
Actual term in a tree

Why?
When the fieldvalue is less than 19 characters the tooltip stays empty. Well empty.. it displays ‘Refine By:’. Every fieldvalue with more than 19 characters is displayed in the tooltip. A ‘parent’ term or a whole path.
How to solve?
This behavior can be solved by adjusting the xslt.
Original xslt:
<a href="{$SecureUrl}" title="{$RefineByHeading}: {$UrlTooltip}">
<xsl:value-of select="Value"/>
</a>
Adjusted xslt:
<xsl:variable name="UrlTooltipAdjusted">
<xsl:call-template name="format-tooltip">
<xsl:with-param name="tooltip" select="$UrlTooltip" />
<xsl:with-param name="string" select="Value" />
</xsl:call-template>
</xsl:variable>
<a href="{$SecureUrl}" title="{$RefineByHeading}: $UrlTooltipAdjusted}">
<xsl:value-of select="Value"/>
</a>
<xsl:template name="format-tooltip">
<xsl:param name="tooltip" />
<xsl:param name="string" />
<xsl:choose>
<xsl:when test="$tooltip != ''">
<xsl:value-of select="$tooltip" />
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$string" />
</xsl:otherwise>
</xsl:choose>
</xsl:template>
The ‘format-tooltip’ template checks if the tooltip is empty and replaces the tooltip value with the actual fieldvalue if so.
By doing this the tooltip will never be empty and will always show the value of the fieldvalue.

Summary
Besides the fieldvalues also the tooltip values suffer from a character limitation. The values of the refinement panel have a 19 character display limit, the tooltip doesn’t display the value when the fieldvalue is less than 19 characters.
This and the previous post solve these issues by making minor adjustments to the OOTB xslt.
Refinement panel character display limitation
Search refiners can contain managed metadata fields to refine the results. Sometimes the display mode of the values look a bit weird in the refinement panel.
Suppose a sitecolumn of a library is a managed metadata column bound to a global termset. The termset is the parent of a few terms and all of these terms have one or more children itself. A termtree.
The display format of the column is set to ‘Display the entire path to the term in the field’.

A few documents are uploaded to the library and the metadata column is set to one of the terms.
A full crawl is completed and the refinement panel shows the metadata refiner.
The refinement panel now looks like this:

As can be seen, not the whole fieldvalue is displayed. That’s weird. How do I know which one to use if not the whole value can be seen?
Maybe it’s a css issue or the left column of the screen isn’t wide enough? Starting up Firebug and checking out the value:

The whole value isn’t present as text to display in the panel! I was seriously surprised!
SharePoint returns only the first 19 characters and three dots…
But… hover over de terms and the whole path is displayed. But that’s not a satisfactory solution, the values have to be displayed properly!
Ok, I agree displaying the whole term tree path isn’t that useful in this case, but it’s needed somewhere else in the site, so the display format of the site column has to stay ‘Display the entire path to the term in the field’.
It would be great to have on option to show only the last term value despite the column display format. An excellent configuration place would be an extra attribute in the filter categories definition xml.
Displaying the last term value
The xslt of the refinementpanel can be adjusted to display the last term value now we know the tooltip does know the whole value.
Original xslt:
<a href="{$SecureUrl}" title="{$RefineByHeading}: {$UrlTooltip}">
<xsl:value-of select="Value"/>
</a>
The new xslt looks a little bit different than that.
First the fieldvalue has to be analyzed if it contains ‘:’. The ‘:’ means the value is a child term and the whole tree path is displayed.
From the value which contains the whole tree path the last term is filtered by a recursive xslt template ´substring-after-last´.
Then a check has to be performed if the last term value contains the three dots. If it does, the last term value should be taken from the tooltip value, because the xslt Value doesn’t contain this value. Confusing, isn’t it?
<xsl:variable name="PartOfValue"> <xsl:call-template name="substring-after-last"> <xsl:with-param name="string" select="Value" /> <xsl:with-param name="delimiter" select="':'" /> </xsl:call-template> </xsl:variable> <xsl:variable name="PartOfTooltip"> <xsl:call-template name="substring-after-last"> <xsl:with-param name="string" select="$UrlTooltip" /> <xsl:with-param name="delimiter" select="':'" /> </xsl:call-template> </xsl:variable> <xsl:choose> <xsl:when test="($FilterCategoryType = 'Microsoft.Office.Server.Search.WebControls.TaxonomyFilterGenerator') and ($PartOfValue != '')"> <xsl:if test="not(contains($PartOfValue, '…'))"> <xsl:value-of select="$PartOfValue"/> </xsl:if> <xsl:if test="contains($PartOfValue, '…')"> <xsl:value-of select="$PartOfTooltip"/> </xsl:if> </xsl:when> <xsl:otherwise> <xsl:value-of select="Value"/> </xsl:otherwise> </xsl:choose>
If the fieldvalue contains less than 19 characters, no dots are displayed and the value can be used, but in that case the urltooltip is empty… To solve an empty tooltip, check out my next post.
After the xslt has been implemented the refinementpanel looks like the picture below

And the tooltip displays the whole term tree:

SharePoint returns only the first 19 characters, so what happens when a term itself exists of 19 or more characters?

On the one hand it’s great the 19 character limitation of displaying a whole termtree isn’t applied to this term, on the other hand, it doesn’t look very nice when the text continues outside the refinement panel.
Summary
The values of the refinement panel have a 19 character display limit. When displaying a whole termtree it’s likely this limitation will be exceeded. Just a few xslt adjustments are necessary to display the fieldvalues correct again.
Ever tried to update a user subtype from code?
User subtypes are one of the many new and nice things in SharePoint 2010.
The other day I was editing user profiles and changed the subtype for this profile in code. After changing the user subtype Commit() was called and I thought I was done.
But then it just started, because the user profile wasn’t updated at all. No exception, no message at all, just the old user subtype.
The used code:
ProfileSubtypeManager psubm = ProfileSubtypeManager.Get(context); ProfileSubtype newSubtype = psubm.GetProfileSubtype(newSubtypeName); currentUserProfile.ProfileSubtype = newSubtype; currentUserProfile.Commit();
Changing the user subtype in the UI really updated the setting, so it was time to debug the SharePoint UserProfiles assembly.
The short version of what the debugging session(s) told me:
A UserProfileUpdateWrapper was created with the following xml
<?xml version="1.0" encoding="utf-16"?> <MSPROFILE> <PROFILE ProfileName="UserProfile"> <USER NewUser="0" NTAccount="account" UserID="3db01e67-abb0-4946-8fa8-85943768cb79">
The next step is iterating through the user profile fields to check if the value ‘IsDirty’ aka the value has been changed. This is the only trigger to actually update a user profile.
When adjusting the user subtype from the UI a few properties are updated, even when they’re not changed. The final XML looks like the following:
<?xml version="1.0" encoding="utf-16"?> <MSPROFILE> <PROFILE ProfileName="UserProfile"> <USER NewUser="0" NTAccount="account" UserID="3db01e67-abb0-4946-8fa8-85943768cb79"> <PROPERTY PropertyName="Assistant" Privacy="1" PropertyValue="" /> <PROPERTY PropertyName="PictureURL" Privacy="1" PropertyValue="" /> <PROPERTY PropertyName="SPS-TimeZone" Privacy="1" PropertyValue="" /> </USER> </PROFILE> </MSPROFILE>
and a real update of the user profile occurred.
To make the update work from code appearently another property has to be updated together with the change of subtype. After a test with an update of a random property, the user subtype was updated too.
Summary
Changing only the user subtype from code, does trigger the Commit() method, but doesn’t call the update profile, because no user profile property was changed. Use a dummy property to update every time the user subtype has changed.
How to delete crawled properties
You all know by now how to delete crawled properties and that you’re not able to delete a single crawled property. When deleting crawled properties, all unmapped properties from a single category get deleted.
- In Central Administration select ‘Manage service applications’
- Select the Search Service Application
- Select ‘Metadata properties’
- Select ‘Categories’
- Edit the category of your choice
- Select ‘Delete all unmapped crawled properties’
- Select ‘Ok’
First thing to notice here: it deletes only unmapped crawled properties. So if your crawled property is still mapped, remove this first.
Second thing: make sure the crawled property isn’t included in the index!
First there are two crawled properties in the SharePoint category (well, there are more, I selected two to see the difference…) :

One is included in the index, the other isn’t.
Next step is to clear the SharePoint category by following all the steps above. The result:

The crawled property included in the index is still present! Even if a full index reset has been performed and the category has been cleaned up, the crawled properties doesn’t get deleted when ‘Included in index’ is set to ‘Yes’.
Summary
Besides unmapping a crawled property, deselect ‘Included in index’ in the crawled property’s properties to delete a crawled property.
This is a valid and working solution for the most of the crawled properties and certainly your custom ones.
When you’re going to test this youself, you’ll notice some of the OOTB unmapped and not include in the index crawled properties will still be present after performing the steps above. This is the case because SharePoint uses some hidden managed properties which are mapped to these crawled properties. Steve Curran explains this in his post which was written for MOSS 2007, but the same principle is still valid for SharePoint 2010:
In table MSSCrawledProperties ows_BaseName can be found with CrawledPropertyId 192.
In table MSSSchemaPropertyMappings CrawledPropertyId 192 is mapped to PID 2147418032.
In table MSSManagedProperties PID 2147418032 is mapped to property TempTitle with ‘Hidden’ and ‘NoDelete’ set to 1:
PowerShell Foreach vs ForEach-Object
There are two variants of ‘for each’ in PowerShell:
Foreach statement: iterates over a collection of objects
ForEach-Object: obtains its entries from the pipeline
At first they both seemed to do the job, but there are some differences.
Let’s do a test with a simple array of items and loop through it using both foreach methods. To measure the time elapsed to loop the array the Measure-Command is used.
$items = 1,2,3,4,5,6,7,8,9,0,10,12,13,14,15,52,58,41,59,841,5,4,1
Write-Host "ForEach-Object: "
(Measure-Command {Â `
 $items | ForEach-Object { `
  "Item: $_" `
 }}).totalmilliseconds
Write-Host "Foreach: "
(Measure-Command {Â `
 Foreach ($item in $items) { `
  "Item: $element" `
 }}).totalmilliseconds
The results differ a lot!
When to use which method?
When the items of the array are known at forehand, like in the test, foreach is the better approach because of the speed. This kind of speed can only be reached when all the objects are already known and stored in a variable.
ForEach-Object is a different story. When the items have to be collected before the loop starts and this can take a while: use ForEach-Object.
This method processes the objects collected in the array directly when available and doesn’t wait until all objects are collected.
SPHttpUtility vs HTTPUtility
Comparison between SPHttpUtility and HTTPUtility – encoding and decoding
There are different ways of encoding and decoding querystring parameters, for example by using SPHttpUtility or HttpUtility.
While programming SharePoint I always tend to use the SPHttpUtility class, but I didn’t know exactly why. Until I accidentally used the HttpUtility and SPHttpUtility at the same time: I noticed some differences. Â
Encode
SharePoint has a Utilities namespace, Microsoft.SharePoint.Utilities, which provides the SPHttpUtility class. One of the methods in this class is UrlKeyValueEncode with several overloads.
The description of the methodÂ
UrlKeyValueEncode(string keyOrValueToEncode)
is ‘Encodes the specified URL query string key or value’.Â
The HttpUtility class in the namespace System.Web contains a method UrlEnode, also with overloads. The description of
UrlEncode(string str)
is ‘Encodes a URL string’.
The HttpUtility class doesn’t have a method to encode a query string key or value as UrlKeyValueEncode, but this is the best match. Â
Let’s encode a space:
The result while encoding with HttpUtility is ‘+’, encoding with SPHttpUtility results in a ‘%20′.
One of the major differences is the casing of the encoded characters. SPHttpUtility encodes the characters uppercase, HttpUtility lowercase.
Another difference can be seen in the picture below: HttpUtility doesn’t encode all characters, SPHttpUtility does:Â Â
Decode
To decode characters the SPHttpUtility class provides the method
UrlKeyValueDecode(string keyOrValueToDecode)
The couterpart of the UrlEncode method in the HttpUtility class is
UrlDecode(string str)
While encoding results in different outcome, decoding doesn’t.
As can be seen in the picture of the encoded characters above, HttpUtility doesn’t encode e.g. ‘(‘, ‘!’, ‘*’. When decoding these (unencoded) characters with SPHttpUtility the results stay ‘(‘, ‘!’, ‘*’. Check the pictures below.
Encoded with HttpUtility, decoded these characters:Â Â
SPHttpUtility encodes characters ‘(‘, ‘!’ and ‘*’ as ‘%28′, ‘%21′ and ‘%2A’. When decoding these characters with SPHttpUtility, but also with HttpUtility, the results are the same:Â Â
Summary
Since decoding gives the same results with SPHttpUtility and HttpUtility, why bother the encoding method? Â
Well, something inside me tells me SharePoint is using it somewhere internally. I didn’t figure out where, but why is the SPHttpUtility implemented if SharePoint easily could use HttpUtility?
Besides some feelings, the SPHttpUtility doesn’t use HttpUtility internally. When checking out the SPHttpUtility.UrlKeyValueEncode with ILSpy, the encoded values, uppercase(!), are listed is the readonly string array s_crgstrUrlHexValue.
Wikipedia has a definition of percent encoding (http://en.wikipedia.org/wiki/Percent-encoding) :
‘Percent-encoding, also known as URL encoding, is a mechanism for encoding information in a Uniform Resource Identifier (URI) under certain circumstances’Â Â
According to this article reserved characters (Reserved characters are those characters that sometimes have special meaning) must be encoded…
According to RFC 3986 reserved characters are:
So HttpUtility doesn’t encode the first five characters, SPHttpUtility encodes all reserved characters. Â
To be compatible with 3986 standard it seems SPHttpUtility is the best option to use.
How to retrieve document set version history
Document set versions are slightly different than item versions. Document sets can be managed by a separate ribbon tab called Document Set and group called Manage.

To create a version of a document set the action Capture Version in this part of the ribbon has to be selected. When selecting the following screen will be shown:

To use versioning of a document set (and items) versioning has to be enabled on the library.   Â
After selecting a version option (when major/minor enabled), adding some comment and selecting the Ok button a document set version is created. To view the versions of the document set the action Version History can be selected in the ribbon.

In this screen the first column displayed is No. This is not the regular version column of the library, but a totally different one. When creating a document set version the version column of the library doesn’t change, only the No value.   Â
That’s nice, but where is the version of the document set actually stored?   Â
The version(s) of a document set are stored in the propertybag of the item itself.   Â
To analyze settings I always start up PowerShell first to check on things. Just because it’s quick and easy. When I get what I want from PowerShell it’s easily turned into C# code. I followed the same procedure to get to the storage of document set versions. Since I couldn’t find the version anywhere in the UI, my first guess was checking the propertybag keys.   Â
$site=Get-SPSite "http://sp2010dev"
$docList = $site.RootWeb.Lists.TryGetList("Documents");
$item = $docList.Items.GetItemById(2)
$prop = $item.Properties
Often I use PowerGui Script Editor which gives an excellent overview of variables:Â Â Â Â
While scrolling through the property keys I noticed a key named snapshots. By checking out the value of that key I knew I found it!   Â
The following PowerShell command can be used to get the value of the snapshot key:Â Â Â Â
$item.Properties.get_Item("snapshots")
The version history is stored in xml:Â Â Â Â
<SnapshotCollection NextSnapshotNumber="3" NextInternalId="1">
<Items />
<Snapshots>
<Snapshot Label="2" Major="True" Created="08/21/2011 07:50:56" By="username">
<Comments>Another version of the document set.</Comments>
<Fields>
<Field Id="8553196d-ec8d-4564-9861-3dbe931050c8">Document set name</Field>
<Field Id="fa564e0f-0c70-4ab9-b863-0177e6ddd247">Document set name</Field>
<Field Id="cbb92da4-fd46-4c7d-af6c-3128c2a5576e">Add a description here.</Field>
</Fields>
<SnapshotItems />
</Snapshot>
<Snapshot Label="1" Major="True" Created="08/21/2011 07:50:20" By="username">
<Comments>This is the first version of this document set.</Comments>
<Fields>
<Field Id="8553196d-ec8d-4564-9861-3dbe931050c8">Document set name</Field>
<Field Id="fa564e0f-0c70-4ab9-b863-0177e6ddd247">Document set name</Field>
<Field Id="cbb92da4-fd46-4c7d-af6c-3128c2a5576e" />
</Fields>
<SnapshotItems />
</Snapshot>
</Snapshots>
</SnapshotCollection>
  Â
The Snapshot element with Label attribute 1 is the first version. The comment is displayed and the fields and values of the document set.   Â
The Snapshot element with Label attribute 2 is the second version. The same items are displayed with the addition of the value of the description ‘Add a description here’. That’s what I changed before creating the second version.   Â
The attribute NextSnapshotNumber holds the value of the version number that will be created when creating another version, 3 in this case.   Â
Summary Â
Document set versions are different than regular item versions. The version history of a document set is stored in the propertybag of the document set itself as xml.
PowerShell – Choose between colored host text or write to an output file? Not anymore!
In PowerShell multiple Write statements are available. The two statements I want to address are Write-Host and Write-Output.Â
What do these two do?
Write-Host: Writes customized output to a host
Write-Output: Sends the specified objects to the next command in the pipeline. If the command is the last command in the pipeline, the objects are displayed in the consoleÂ
An example of Write-Host
Write-Host "Write-Host statement..."
The result displayed in the hostÂ
An example of Write-Output
Write-Output "Write-Output statement..."
The result displayed in the host
At this point there is no difference in the result of these two statements.Â
Write-Host with ForegroundColorÂ
A nice parameter of Write-Host is -ForegroundColor. Using this parameter with a color, the text displayed in the host has the color specified. I find this very useful to quickly see if a script has succeeded or failed. I always display the success message in green, the failed message in red.  Â
To show this the existence of a SPList will be checked. If it doesn´t exist, it will be created using the following statement:  Â
$sampleListName = "PS List"
$siteUrl=http://sp2010dev
$site = Get-SPSite $siteUrl
$web = $site.RootWeb</pre>
function CreateList($listName){
$web.Lists.Add($listName, "Description for list", [Microsoft.SharePoint.SPListTemplateType]::GenericList)
}
function CheckIfListExists(){
$currentList = $web.Lists.TryGetList($sampleListName)
if($currentList -ne $null){
Write-Host "List exists" -ForegroundColor Green
}
else{
Write-Host "List doesn't exist, creating now..." -ForegroundColor Red
CreateList $sampleListName
Write-Host "Check if list exist..."
CheckIfListExists
}
}
Write-Host "Calling CheckIfListExists ..."
CheckIfListExists
If the list exists a message with green colored text will appear: ‘List exists’, else a message with red colored text will appear: ‘List doesn’t exist, creating now…’, followed by the actual creation of the list. After this the existence of the list is check again. As you can see if the list creation fails the code will be stuck in an infinite loop, so don´t use this as production code…  Â
Outcome when the list doesn´t exist and is created:
Outcome when the list already exists:<picture PSWrite02>
Write-Output with output to file  Â
A nice option of Write-Output is the possibility to write the output to a file on the filesystem.  Â
$file = "C:\_Tools\OutputFile.txt" Write-Output "Write-Output statement..." Write-Output "Write-Output statement..." | Out-File $file
The first Write-Output statement writes the output to the host, the second to the file (but not to the host).  Â
Best of both worlds?  Â
Ofcourse Write-Host as well as Write-Output has a lot more options to use, but I want to point out something here.
Write-Host can write colored messages to the host, but it can’t write output to a file.
Write-Output can’t write colored messages to the host, but it can write output to a file.  Â
What if I want to:Â Â Â
write colored messages to the host if I decide to output to the host AND
write messages to a file just by using ‘| Out-File $file’
With the current possibilities of both operations I have to choose between:
1. colored messages (and nothing written to the output file) or put the output to a file and host, but no colored messages displayed in the hostÂ
2. write double statements; Write-Host with -ForeGroundColor to write the colored output to the host and Write-Output to write the output to a file when using ‘| Out-File $file’.  Â
Let me clarify the second option with an example.
Write-Output "Write-Output statement..." | Out-File $file Write-Host "Write-Host statement..." -ForegroundColor Blue
Write-Output writes the message to the file specified in $file and is not written to the host.
Write-Host writes the message to the host in the color blue.
Just as expected and just want I wanted. But I have to write the messages twice.
Another option:Â Â Â
Write-Output "Write-Output statement..." Write-Host "Write-Host statement..." -ForegroundColor Blue
The code above is saved in a file and called by:Â Â Â
PS C:\_Tools> .\PSScriptFile.ps1
Result: messages appear twice in the host.
Output it to a file:Â Â Â
PS C:\_Tools> .\PSScriptFile.ps1 | Out-File $file
Result: No message in the host, but a message in the file!
Still, the messages have to be written twice in the file: Write-Host and Write-Output…
Do I really have to write all the messages twice to show them colored in the host and write them to an output file?
Actually, there is no possibility to make Write-Host write to an output file.
But the host itself can be accessed to change its text color (and more) and use Write-Output to write to the host (in color!) and to an output file.
The host itself can be accessed by $Host.  Â
$Host.Name
When using PowerGUI Script Editor the results of the above statement is: PowerGUIScriptEditorHost
Executing the same statement in the console the result is: ConsoleHost
That’s awesome, $Host knows who he is!
Let’s try to get the text color of the host:
$currentColor = $Host.UI.RawUI.ForegroundColor
PowerGUI Script Editor:
Console:
So what about changing the text color of the host?  Â
function WriteCustomOutput($message, [System.ConsoleColor]$foregroundcolor)
{
currentColor = $Host.UI.RawUI.ForegroundColor
$Host.UI.RawUI.ForegroundColor = $foregroundcolor
if ($message)
{
Write-Output $message
}
$Host.UI.RawUI.ForegroundColor = $currentColor
}
WriteCustomOutput -message "WriteColoredOutput statement..." -foregroundcolor Green
And the result in the host:
Let’s save the code to a file and call the file from the console:
And will the output be written to an output file when using the statement:
.\PSWriteCustomOutput.ps1 | Out-File OutputFile.txt
Yes it is written to the file:
Summary
Write-Host and Write-Output are very simple and useful statements. Sometimes the best of both is wished for.
With some creativity you can have both. Use WriteCustomOutput!
To ‘this’ or not to ‘this’ with the Client Object model
Recently I developed a CustomAction on a list with some client script in the CommandAction. Nothing fancy or new.
I put a .js file in the _layouts folder and referenced the file by a CustomAction with Location ‘ScriptLink’ and ScriptSrc. Put some code in the file to get some data I needed and called executeQueryAsync with two delegates like this:
clientContext.executeQueryAsync(Function.createDelegate(this, this.OnSucceeded), Function.createDelegate(this, this.OnFailed));
Deployed as a Farm solution on the environment and everything went well so far.
After this, minds changed and it had to become a sandboxed solution. Ok, let’s do it.
1. Set the Sandboxed Solution property to True on the project
2. Removed the CustomAction with Location=’ScriptLink’
3. Put the code from the js file from the _layouts folder in the CommandUIHandler’s attribute CommandAction
4. Deployed the sandboxed solution
I always use FireFox when programming and all of a sudden I received the following error:
b is undefined
![]()
and things stopped working. While in the Farm solution the CustomAction worked as expected and the OnSucceeded and OnFailed were executed.
I put in some alert statements to see where the code broke and it seemed the OnSucceeded and the OnFailed methods weren’t executed at all.
By removing the ‘this’ keyword in the createDelegate everything went well again:
clientContext.executeQueryAsync(Function.createDelegate(this, OnSucceeded), Function.createDelegate(this, OnFailed));
This behaviour seems a bit strange to me. When putting the code in a separate js file and deploying it to the _layouts folder the ‘this’ keyword can be used, but putting the exact same code in the CommandAction of CommandUIHandler the OnSucceeded and OnFailed methods can’t be found anymore using the ‘this’ keyword.
By the way, in IE you will receive the following error:
‘b’ is null or not an object

Client side social dashboard with SharePoint 2010 and SPServices
The social dashboard functionality
|
Functionality
Â
|
Employee
Â
|
Manager
Â
|
Board member
Â
|
|
Tags of current user
Â
|
V
Â
|
V
Â
|
V
Â
|
|
Most used tags
Â
|
V
Â
|
V
Â
|
V
Â
|
|
Drill down to url
Â
|
V
Â
|
V
Â
|
V
Â
|
|
Top active users
Â
|
V
Â
|
V
Â
|
V
Â
|
|
Drill down to tag
Â
|
X
Â
|
V
Â
|
V
Â
|
|
Activity of employees in own department
Â
|
X
Â
|
V
Â
|
V
Â
|
|
Activity of employees in a selectable department
Â
|
X
Â
|
X
Â
|
V
Â
|
<script src="/jQueryLibrary/jquery-1.4.4.min.js" type="text/javascript"></script> <script src=" /jQueryLibrary/jquery.SPServices-0.5.8.min.js" type="text/javascript"></script> <script src=" /jQueryLibrary/jquery.tmpl.js" type="text/javascript"></script>
Tags of current user
var currentUserAccount = $().SPServices.SPGetCurrentUser({
           fieldName: "Name"
       });
$().SPServices({
   operation: "GetTagsOfUser",
   userAccountName: $().SPServices.SPGetCurrentUser(),
   completefunc: function (xData, Status) {
       $(xData.responseXML).find("SocialTagDetail").each(function () {
           tagName = $("Term>Name", $(this)).text();
           tagsofuser.push({ Tag: tagName, Count: 1 });
       });
       tagsofuser = uniqueTags(tagsofuser);
       SortByCount(tagsofuser);
       $("#currentUserTagsText").show();
       $("#currentUserTags").html("");
       $("#tagsofuserTemplate").tmpl(tagsofuser)
           .appendTo("#currentUserTags");
   }
});
<?xml version="1.0"?> <soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">  <soap:Body>    <GetTagsOfUserResponse xmlns="http://microsoft.com/webservices/SharePointPortalServer/SocialDataService">      <GetTagsOfUserResult>        <SocialTagDetail>          <Url>http://sp2010/Lists/Tasks/AllItems.aspx</Url>          <Owner>sp2010\mark</Owner>          <LastModifiedTime>2010-12-19T13:28:09.437</LastModifiedTime>          <Title>Tasks - All Tasks</Title>          <Term>            <Id>974a854f-31b4-431f-91cb-a6289f58c978</Id>            <Name>I like it</Name>          </Term>          <IsPrivate>false</IsPrivate>        </SocialTagDetail>        Rest of the SocialTagDetails are intentionally left out�      </GetTagsOfUserResult>    </GetTagsOfUserResponse>  </soap:Body> </soap:Envelope>
<div><script id="tagsofuserTemplate" type="text/x-jquery-tmpl">
<div>Â </div>
<div><div style="float:left;width:40%">
<div>Â </div>
<div>Â Â Â Â Â Â Â ${Tag}
<div>Â </div>
<div></div>
<div>Â </div>
<div><div style="float:left;width:20%">
<div>Â </div>
<div>Â Â Â Â Â Â Â ${Count}
<div>Â </div>
<div></div><br />
<div>Â </div>
<div></script>
<div>
Most used tags
$().SPServices({
   operation: "GetAllTagTerms",
   debug: false,
   completefunc: function (xData, Status) {
       $(xData.responseXML).find("SocialTermDetail").each(function () {
           termName = $("Term>Name", $(this)).text();
           termGuid = $("Term>Id", $(this)).text();
           counter = $("Count", $(this)).text();
           terms.push({ Term: termName, Count: counter, TermGuid: termGuid });
       });
       SortByCount(terms);
       terms.length = 5;
       $("#showterms").html("");
       $("#termTemplate").tmpl(terms)
           .appendTo("#showterms");
   }
});
<div><div style="float:left;width:40%">
<div>Â </div>
<div>Â Â Â Â <a href="#" id=${TermGuid}>
<div>Â </div>
<div>Â Â Â Â Â Â Â ${Term}
<div>Â </div>
<div>Â Â Â </a>
<div>Â </div>
<div></div>
<div>Â </div>
<div><div style="float:left;width:20%">
<div>Â </div>
<div>Â Â Â Â Â Â Â ${Count}
<div>Â </div>
<div></div>
<div>
   $().SPServices({
       operation: "GetAllTagUrls",
       termID: termId,
       debug: true,
       completefunc: function (xData, Status) {
           $(xData.responseXML).find("SocialUrlDetail").each(function () {
               url = $("Url", $(this)).text();
               countUrl = $("Count", $(this)).text();
               urlsofterm.push({ Url: url, Count: countUrl });
           });
           SortByCount(urlsofterm);
           $("#urlsoftermContainer").show();
           $("#showurlsofterm").html("");
           $("#urlTemplate").tmpl(urlsofterm)
                               .appendTo("#showurlsofterm");
       }
   });

Top active users
$().SPServices({
   operation: "GetUserCollectionFromSite",
   completefunc: function (xData, Status) {
       $(xData.responseXML).find("User").each(function () {
           userName = $(this).attr("LoginName");
           userNames.push({ UserName: userName });
       });
       GetTopTagsOfUsers(userNames);
   }
});
function CountTagsOfUser(useraccountname, f) {
   var tagCount = "";
   var tagsofuser = [];
   $().SPServices({
       operation: "CountTagsOfUser",
       userAccountName: useraccountname,
       debug: true,
       completefunc: function (xData, Status) {
           $(xData.responseXML).find("CountTagsOfUserResult").each(function () {
               tagCount = $(this).text();
               tagsofuser.push({ Count: tagCount, UserAccountName: useraccountname });
           });
           SortByCount(tagsofuser);
           if (typeof f == "function") f(tagsofuser);
           return tagsofuser;
       }
 });
}
function GetTopTagsOfUsers(usernames) {
   var result = [];
   $.each(usernames, function (key, value) {
       CountTagsOfUser(value["UserName"], function (items) {
           $.each(items, function (i, n) {
               result.push({ Count: n["Count"], UserAccountName: n["UserAccountName"] });
           });
          if (usernames.length == result.length) {
               SortByCount(result);
               result.length = 5;
               $("#showcounttagsofuser").html("");
               if (isCEO || isManager) {
                   $("#counttagsofuserTemplate").tmpl(result)
                   .appendTo("#showcounttagsofuser");
               } else {
                   $("#counttagsofuserTemplateForUser").tmpl(result)
                   .appendTo("#showcounttagsofuser");
               }
           }
       });
   });
}
<script id="counttagsofuserTemplateForUser" type="text/x-jquery-tmpl">
<div style="float:left;width:40%">
       ${UserAccountName}
</div>
<div style="float:left;width:20%">
       ${Count}
</div>
</script>
<script id="counttagsofuserTemplate" type="text/x-jquery-tmpl">
<div style="float:left;width:40%">
  <a href="#" id=${UserAccountName}>
       ${UserAccountName}
   </a>
</div>
<div style="float:left;width:20%">
       ${Count}
</div>
</script>
What’s the difference between a ‘regular’ employee, a manager and a board member?
|
UserName
Â
|
Department
Â
|
Manager
Â
|
Role
Â
|
|
Alex
Â
|
ICT
Â
|
Andrew
Â
|
Employee
Â
|
|
Andrew
Â
|
ICT
Â
|
Â
Â
|
Manager
Â
|
|
Anita
Â
|
Marketing
Â
|
Mark
Â
|
Employee
Â
|
|
Chris
Â
|
HR
Â
|
Dave
Â
|
Employee
Â
|
|
Dave
Â
|
HR
Â
|
Â
Â
|
Manager
Â
|
|
Jeff
Â
|
Marketing
Â
|
Mark
Â
|
Employee
Â
|
|
Mark
Â
|
Marketing
Â
|
Â
Â
|
Manager
Â
|
|
Paul
Â
|
CEO
Â
|
Â
Â
|
Board member
Â
|
var CEOdepartment = "CEO";
$().SPServices({
  operation: "GetUserProfileByName",
   AccountName: currentUserAccount,
   completefunc: function (xData, Status) {
       $(xData.responseXML).find("GetUserProfileByNameResult>PropertyData").each(function () {
           //check for CEO department
           if ($("Name", $(this)).text().toUpperCase() == "Department".toUpperCase()) {
               departmentOfCurrentUser = $("Values>ValueData>Value", $(this)).text();
               if (departmentOfCurrentUser.toUpperCase() == CEOdepartment.toUpperCase()) {
                   isCEO = true;
                   GetDepartmentsAndUsers();
               }
           }
           else if ($("Name", $(this)).text().toUpperCase() == "Manager".toUpperCase()) {
               managerName = $("Values>ValueData>Value", $(this)).text();
               if (managerName == "") {
                   if (!isCEO) {
                       isManager = true;
                       GetDepartmentsAndUsers();
                   }
               }
           }
       });
   }
});
<?xml version="1.0"?> <soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"> Â <soap:Body> Â Â Â <GetUserProfileByNameResponse xmlns="http://microsoft.com/webservices/SharePointPortalServer/UserProfileService"> Â Â Â Â Â <GetUserProfileByNameResult> Â Â Â Â Â Â Â <PropertyData> Â Â Â Â Â Â Â Â Â <IsPrivacyChanged>false</IsPrivacyChanged> Â Â Â Â Â Â Â Â Â <IsValueChanged>false</IsValueChanged> Â Â Â Â Â Â Â Â Â <Name>AccountName</Name> Â Â Â Â Â Â Â Â <Privacy>Public</Privacy> Â Â Â Â Â Â Â Â Â <Values> Â Â Â Â Â Â Â Â Â Â Â <ValueData> Â Â Â Â Â Â Â Â Â Â Â Â Â <Value xsi:type="xsd:string">sp2010\paul</Value> Â Â Â Â Â Â Â Â Â Â Â </ValueData> Â Â Â Â Â Â Â Â Â </Values> Â Â Â Â Â Â Â </PropertyData> Â Â Â Â Â Â Â <PropertyData> Â Â Â Â Â Â Â Â Â <IsPrivacyChanged>false</IsPrivacyChanged> Â Â Â Â Â Â Â Â Â <IsValueChanged>false</IsValueChanged> Â Â Â Â Â Â Â Â Â <Name>Department</Name> Â Â Â Â Â Â Â Â Â <Privacy>Public</Privacy> Â Â Â Â Â Â Â Â Â <Values> Â Â Â Â Â Â Â Â Â Â Â <ValueData> Â Â Â Â Â Â Â Â Â Â Â Â Â <Value xsi:type="xsd:string">CEO</Value> Â Â Â Â Â Â Â Â Â Â Â </ValueData> Â Â Â Â Â Â Â Â Â </Values> Â Â Â Â Â Â Â </PropertyData> Â Â Â Â Â </GetUserProfileByNameResult> Â Â Â </GetUserProfileByNameResponse> Â </soap:Body> </soap:Envelope>
Activity of employees in own or a selectable department
Â
var queryTextSQL = "<QueryPacket xmlns='urn:Microsoft.Search.Query' Revision='1000'>"
queryTextSQL += "<Query>"
queryTextSQL += "<Context>"
queryTextSQL += "<QueryText language='en-US' type='MSSQLFT'>"
if (isCEO) {
   queryTextSQL += "SELECT Title, Rank, Size, Description, Write, Path, AccountName, Department FROM scope() WHERE ( (\"SCOPE\" = 'People') ) ORDER BY \"Rank\" DESC"
} else {
   queryTextSQL += "SELECT Title, Rank, Size, Description, Write, Path, AccountName, Department FROM scope() WHERE ( (\"SCOPE\" = 'People') ) AND (CONTAINS (Department,'" + departmentOfCurrentUser + "')) ORDER BY \"Rank\" DESC"
}
queryTextSQL += "</QueryText>"
queryTextSQL += "</Context>"
queryTextSQL += "</Query>"
queryTextSQL += "</QueryPacket>";
$().ready(function () {
   var resultText = "";
   $().SPServices({
       operation: "QueryEx",
       queryXml: queryTextSQL,
      completefunc: function (xData, Status) {
           $(xData.responseXML).find("RelevantResults").each(function (i) {
               accountName = $("ACCOUNTNAME", $(this)).text();
               departments[i] = $("DEPARTMENT", $(this)).text();
               users.push({ AccountName: accountName, Department: departments[i] });
           });
           if (isCEO) {
               $('#departmentContainer').show();
               fillDepartmentsDropdown('#departmentSelection', $.unique(departments), "Select department");
           }
           if (isCEO || isManager) {
               $('#userContainer').show();
               fillUsersDropdown('#userSelection', users, "Select user");
           }
       }
   });
});
function fillUsersDropdown(dropdownName, arrayToUse, text) {
   $(dropdownName).html("");
   $.each(arrayToUse,
       function (key, value) {
           $(dropdownName).append('<option value="' + value["AccountName"] + '">' + value["AccountName"] + '</option>');
       });
   $(dropdownName).prepend("<option value='0' selected='true'>" + text + "</option>");
   $(dropdownName).find("option:first")[0].selected = true;
}
   <div style="float: left; width: 100%; display: none;" id="departmentContainer">        <div style="float: left; width: 15%">            Select department</div>        <select id="departmentSelection" style="float: left; width: 15%">        </select>    </div>    <br />    <div id="userContainer" style="float: left; width: 100%; display: none;">        <div style="float: left; width: 15%">            Select user</div>        <select id="userSelection" style="float: left; width: 15%">        </select>        <div style="clear: both; float: left; width: 25%">            <a href="#" onclick="GetTagsOfSelection(userSelection.value, departmentSelection.value);return false">                Show tags of selection</a></div>        <h4 style="clear: both; float: left; display: none;" id="showtagsofuserText">            Tags of selection:</h4>        <div id="showtagsofuser" style="clear: both;">        </div>    </div>
$('select').change(function (e) {
   if (this.id == "departmentSelection") {
       $('#userSelection option').each(function (i, option) {
           $(option).remove();
       });
       j = 0;
       childArray.length = 0;
       if (this[this.selectedIndex].value != 0) {
           departmentSelected = this[this.selectedIndex].text;
           //filter the users array on the selected department
           filteredUsers = $.grep(users, function (filter) {
               return filter["Department"] == departmentSelected;
           });
           fillUsersDropdown('#userSelection', filteredUsers, "Select user");
       }
       else {
           fillUsersDropdown('#userSelection', users, "Select user");
       }
   }
});
function GetTagsOfSelection(userSelection, departmentSelection) {
   var result = [];
   if (userSelection != 0) {
       GetTagsOfUser(userSelection, true, true);
   } else if (departmentSelection != 0) {
       $.each(filteredUsers, function (key, value) {
           GetTagsOfUser(value["AccountName"], false, true, false, function (items) {
               $.each(items, function (i, n) {
                   result.push({ Tag: n["Tag"], Count: 1 });
               });
               result = uniqueTags(result);
               SortByCount(result);
               $("#showtagsofuserText").show();
               $("#showtagsofuser").html("");
               $("#tagsofuserTemplate").tmpl(result)
           .appendTo("#showtagsofuser");
               //}
           });
       });
   }
}























