Working with folders and files via SharePoint 2013 REST in PowerShell

Overview

In the previous post we’ve already discussed how to perform CRUD operations by sending HTTPS requests to SharePoint RESTful web services in PoweShell. The Invoke-RestSPO function was introduced for that purpose since  Invoke-RestMethod cmdlet does not support claims based authentication and it makes this cmdlet impossible to use in O365 and SharePoint Online scenarios.

This time I am going to demonstrate how  to perform basic create, read, update, and delete (CRUD) operations on folders and files with the SharePoint 2013 REST interface using Invoke-RestSPO function.

Explore the REST service files and folder syntax

SharePoint 20123 Files and Folders REST syntax

 

Working with folders

Folder resource: represents a folder on a SharePoint Web site

Endpoint URI: http://<site url>/_api/web/getfolderbyserverrelativeurl(‘/<folder name>‘)

Supported HTTP methods:  GET  |  POST  |  DELETE  |  MERGE  |  PUT

The following examples demonstrates how to perform basic CRUD operations with Folder resource.

 

[System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SharePoint.Client")
[System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SharePoint.Client.Runtime")
. ".\Invoke-RestSPO.ps1"
<#
.SYNOPSIS
Retieve Folder
.DESCRIPTION
Read Folder operation via SharePoint 2013 REST API
url: http://site url/_api/web/GetFolderByServerRelativeUrl('/Shared Documents')
method: GET
headers:
Authorization: "Bearer " + accessToken
accept: "application/json;odata=verbose" or "application/atom+xml"
.NOTES
Prerequisite : Invoke-RestSPO function
.EXAMPLE
$Folder = Get-SPOFolder -WebUrl $WebUrl -UserName $UserName -Password $Password -FolderUrl '/Shared Documents/Folder To Read'
#>
Function Get-SPOFolder(){
Param(
[Parameter(Mandatory=$True)]
[String]$WebUrl,
[Parameter(Mandatory=$True)]
[String]$UserName,
[Parameter(Mandatory=$False)]
[String]$Password,
[Parameter(Mandatory=$True)]
[String]$FolderUrl
)
$Url = $WebUrl + "/_api/web/GetFolderByServerRelativeUrl('" + $FolderUrl + "')"
Invoke-RestSPO $Url Get $UserName $Password
}
<#
.SYNOPSIS
Create Folder
.DESCRIPTION
Create Folder operation via SharePoint 2013 REST API.
url: http://site url/_api/web/folders
method: POST
body: { '__metadata': { 'type': 'SP.Folder' }, 'ServerRelativeUrl': '/document library relative url/folder name'}
Headers:
Authorization: "Bearer " + accessToken
X-RequestDigest: form digest value
accept: "application/json;odata=verbose"
content-type: "application/json;odata=verbose"
content-length:length of post body
.NOTES
Prerequisite : Invoke-RestSPO function
.EXAMPLE
$Folder = Create-SPOFolder -WebUrl $WebUrl -UserName $UserName -Password $Password -FolderUrl '/Shared Documents/Folder To Create'
#>
Function Create-SPOFolder(){
Param(
[Parameter(Mandatory=$True)]
[String]$WebUrl,
[Parameter(Mandatory=$True)]
[String]$UserName,
[Parameter(Mandatory=$False)]
[String]$Password,
[Parameter(Mandatory=$True)]
[String]$FolderUrl
)
$Url = $WebUrl + "/_api/web/folders"
$folderPayload = @{
__metadata = @{'type' = 'SP.Folder' };
ServerRelativeUrl = $FolderUrl;
} | ConvertTo-Json
$contextInfo = Get-SPOContextInfo $WebUrl $UserName $Password
Invoke-RestSPO Url $Url Method Post UserName $UserName Password $Password Metadata $folderPayload RequestDigest $contextInfo.GetContextWebInformation.FormDigestValue
}
<#
.SYNOPSIS
Update Folder
.DESCRIPTION
Update Folder operation via SharePoint 2013 REST API.
url: http://site url/_api/web/GetFolderByServerRelativeUrl('/Folder Name')
method: POST
body: { '__metadata': { 'type': 'SP.Folder' }, 'Name': 'New name' }
Headers:
Authorization: "Bearer " + accessToken
X-RequestDigest: form digest value
"IF-MATCH": etag or "*"
"X-HTTP-Method":"MERGE",
accept: "application/json;odata=verbose"
content-type: "application/json;odata=verbose"
content-length:length of post body
.NOTES
Prerequisite : Invoke-RestSPO function
.EXAMPLE
Update-SPOFolder -WebUrl $WebUrl -UserName $UserName -Password $Password -FolderUrl '/Shared Documents/Folder To Update' -FolderName "New Folder Name"
#>
Function Update-SPOFolder(){
Param(
[Parameter(Mandatory=$True)]
[String]$WebUrl,
[Parameter(Mandatory=$True)]
[String]$UserName,
[Parameter(Mandatory=$False)]
[String]$Password,
[Parameter(Mandatory=$True)]
[String]$FolderUrl,
[Parameter(Mandatory=$True)]
[String]$FolderName
)
$Url = $WebUrl + "/_api/web/GetFolderByServerRelativeUrl('" + $FolderUrl + "')"
$folderPayload = @{
__metadata = @{'type' = 'SP.Folder' };
}
if($FolderName) {
$folderPayload['Name'] = $FolderName
}
$folderPayload = $folderPayload | ConvertTo-Json
$contextInfo = Get-SPOContextInfo $WebUrl $UserName $Password
Invoke-RestSPO Url $Url Method Post UserName $UserName Password $Password Metadata $folderPayload RequestDigest $contextInfo.GetContextWebInformation.FormDigestValue ETag "*" XHTTPMethod "MERGE"
}
<#
.SYNOPSIS
Delete Folder
.DESCRIPTION
Delete Folder operation via SharePoint 2013 REST API.
url: http://site url/_api/web/GetFolderByServerRelativeUrl('/Folder Name')
method: POST
Headers:
Authorization: "Bearer " + accessToken
X-RequestDigest: form digest value
"IF-MATCH": etag or "*"
"X-HTTP-Method":"DELETE"
.NOTES
Prerequisite : Invoke-RestSPO function
.EXAMPLE
Delete-SPOFolder -WebUrl $WebUrl -UserName $UserName -Password $Password -FolderUrl '/Shared Documents/Folder To Delete'
#>
Function Delete-SPOFolder(){
Param(
[Parameter(Mandatory=$True)]
[String]$WebUrl,
[Parameter(Mandatory=$True)]
[String]$UserName,
[Parameter(Mandatory=$False)]
[String]$Password,
[Parameter(Mandatory=$True)]
[String]$FolderUrl
)
$Url = $WebUrl + "/_api/web/GetFolderByServerRelativeUrl('" + $FolderUrl + "')"
$contextInfo = Get-SPOContextInfo $WebUrl $UserName $Password
Invoke-RestSPO Url $Url Method Post UserName $UserName Password $Password RequestDigest $contextInfo.GetContextWebInformation.FormDigestValue ETag "*" XHTTPMethod "DELETE"
}

view raw
Folders-RestSPO.ps1
hosted with ❤ by GitHub

 

Working with files

Folder resource: represents a file in a SharePoint Web site that can be a Web Part Page, an item in a document library, or a file in a folder.

Endpoint URI: http://<site url>/_api/web/getfilebyserverrelativeurl(‘/<folder name>/<file name>‘)

Supported HTTP methods:  GET  |  DELETE  |  POST  (File resource)

The following examples demonstrates how to perform basic operations with File resource including:

  • upload file into SharePoint
  • download  file from a SharePoint

 

[System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SharePoint.Client")
[System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SharePoint.Client.Runtime")
. ".\Invoke-RestSPO.ps1"
<#
.SYNOPSIS
Retieve Files in Folder
.DESCRIPTION
Read Files operation via SharePoint 2013 REST API
url: http://site url/_api/web/GetFolderByServerRelativeUrl('/Folder Name')/Files
method: GET
headers:
Authorization: "Bearer " + accessToken
accept: "application/json;odata=verbose" or "application/atom+xml"
.NOTES
Prerequisite : Invoke-RestSPO function
.EXAMPLE
$Files = Get-SPOFiles -WebUrl $WebUrl -UserName $UserName -Password $Password -FolderUrl '/Shared Documents/Folder'
#>
Function Get-SPOFiles(){
Param(
[Parameter(Mandatory=$True)]
[String]$WebUrl,
[Parameter(Mandatory=$True)]
[String]$UserName,
[Parameter(Mandatory=$False)]
[String]$Password,
[Parameter(Mandatory=$True)]
[String]$FolderUrl
)
$Url = $WebUrl + "/_api/web/GetFolderByServerRelativeUrl('" + $FolderUrl + "')/Files"
Invoke-RestSPO $Url Get $UserName $Password | % { $_.results }
}
<#
.SYNOPSIS
Delete File
.DESCRIPTION
Delete Files operation via SharePoint 2013 REST API
url: http://site url/_api/web/GetFileByServerRelativeUrl('/Folder Name/file name')
method: POST
headers:
Authorization: "Bearer " + accessToken
X-RequestDigest: form digest value
IF-MATCH: etag or "*"
X-HTTP-Method:"DELETE"
.NOTES
Prerequisite : Invoke-RestSPO function
.EXAMPLE
Delete-SPOFile -WebUrl $WebUrl -UserName $UserName -Password $Password -FileUrl '/Shared Documents/Folder/File To Delete'
#>
Function Delete-SPOFile(){
Param(
[Parameter(Mandatory=$True)]
[String]$WebUrl,
[Parameter(Mandatory=$True)]
[String]$UserName,
[Parameter(Mandatory=$False)]
[String]$Password,
[Parameter(Mandatory=$True)]
[String]$FileUrl
)
$Url = $WebUrl + "/_api/web/GetFileByServerRelativeUrl('" + $FileUrl + "')"
$contextInfo = Get-SPOContextInfo $WebUrl $UserName $Password
Invoke-RestSPO Url $Url Method Post UserName $UserName Password $Password RequestDigest $contextInfo.GetContextWebInformation.FormDigestValue ETag "*" XHTTPMethod "DELETE"
}
<#
.SYNOPSIS
Download File
.DESCRIPTION
Read File operation via SharePoint 2013 REST API
url: http://site url/_api/web/GetFileByServerRelativeUrl('/Folder Name/file name')/$value
method: GET
headers:
Authorization: "Bearer " + accessToken
.NOTES
Prerequisite : Invoke-RestSPO function
.EXAMPLE
Download-SPOFile -WebUrl $WebUrl -UserName $UserName -Password $Password -FileUrl '/Shared Documents/Folder/File To Download' -DownloadPath 'c:\downloads'
#>
Function Download-SPOFile(){
Param(
[Parameter(Mandatory=$True)]
[String]$WebUrl,
[Parameter(Mandatory=$True)]
[String]$UserName,
[Parameter(Mandatory=$True)]
[String]$Password,
[Parameter(Mandatory=$True)]
[String]$FileUrl,
[Parameter(Mandatory=$True)]
[String]$DownloadPath
)
$Url = $WebUrl + "/_api/web/GetFileByServerRelativeUrl('" + $FileUrl + "')/`$value"
$fileContent = Invoke-RestSPO Url $Url Method Get UserName $UserName Password $Password BinaryStringResponseBody $True
#Save
$fileName = [System.IO.Path]::GetFileName($FileUrl)
$downloadFilePath = [System.IO.Path]::Combine($DownloadPath,$fileName)
[System.IO.File]::WriteAllBytes($downloadFilePath,$fileContent)
}
<#
.SYNOPSIS
Upload File
.DESCRIPTION
Create File operation via SharePoint 2013 REST API
url: http://site url/_api/web/GetFileByServerRelativeUrl('/Folder Name/file name')
method: POST
headers:
Authorization: "Bearer " + accessToken
X-RequestDigest: form digest value
IF-MATCH: etag or "*"
X-HTTP-Method:"DELETE"
.NOTES
Prerequisite : Invoke-RestSPO function
.EXAMPLE
Upload-SPOFile -WebUrl $WebUrl -UserName $UserName -Password $Password -FolderUrl '/Shared Documents/Folder' -UploadFilePath 'Physical Path to File'
#>
Function Upload-SPOFile(){
Param(
[Parameter(Mandatory=$True)]
[String]$WebUrl,
[Parameter(Mandatory=$True)]
[String]$UserName,
[Parameter(Mandatory=$True)]
[String]$Password,
[Parameter(Mandatory=$True)]
[String]$FolderUrl,
[Parameter(Mandatory=$True)]
[String]$UploadFilePath
)
$FileInfo = New-Object System.IO.FileInfo($UploadFilePath)
$Url = $WebUrl + "/_api/web/GetFolderByServerRelativeUrl('" + $FolderUrl + "')/Files/add(url='" + $FileInfo.Name + "',overwrite=true)"
$FileContent = [System.IO.File]::ReadAllBytes($FileInfo.FullName)
$contextInfo = Get-SPOContextInfo $WebUrl $UserName $Password
Invoke-RestSPO Url $Url Method Post UserName $UserName Password $Password Body $FileContent RequestDigest $contextInfo.GetContextWebInformation.FormDigestValue
}

view raw
Files-RestSPO.ps1
hosted with ❤ by GitHub

Summary

To summarize, it was demonstrates how to perform basic operations with files and folders, in particular how to  download and upload files via REST. For that purpose we  utilized Invoke-RestSPO function  that is intended for sending HTTPS requests to O365/SharePoint Online REST service.

References

Consuming the SharePoint 2013 REST API from PowerShell

Introduction

SharePoint 2013 introduces a Representational State Transfer (REST) service that is comparable to the  SharePoint CSOM and in addition to CSOM, REST API opens up a huge capabilities, in particular for administering and automating SharePoint Online when used with PowerShell.

Sending  REST requests to a SharePoint Online 

In the previous post we’ve already covered how to perform read operations by sending HTTPS requests to SharePoint RESTful web services. This time we are going to extend PowerShell script  in order to support all the CRUD operations.

The Invoke-RestSPO function sends  HTTPS requests to SharePoint REST web services that returns richly structured data (JSON)

Add-Type –Path "C:\Program Files\Common Files\microsoft shared\Web Server Extensions\15\ISAPI\Microsoft.SharePoint.Client.dll"
Add-Type –Path "C:\Program Files\Common Files\microsoft shared\Web Server Extensions\15\ISAPI\Microsoft.SharePoint.Client.Runtime.dll"
<#
.Synopsis
Sends an HTTP or HTTPS request to a SharePoint Online REST-compliant web service.
.DESCRIPTION
This function sends an HTTP or HTTPS request to a Representational State
Transfer (REST)-compliant ("RESTful") SharePoint Online web service.
.EXAMPLE
Invoke-SPORestMethod -Url "https://contoso.sharepoint.com/_api/web&quot;
.EXAMPLE
Invoke-SPORestMethod -Url "https://contoso.sharepoint.com/_api/contextinfo&quot; -Method "Post"
#>
Function Invoke-RestSPO(){
Param(
[Parameter(Mandatory=$True)]
[String]$Url,
[Parameter(Mandatory=$False)]
[Microsoft.PowerShell.Commands.WebRequestMethod]$Method = [Microsoft.PowerShell.Commands.WebRequestMethod]::Get,
[Parameter(Mandatory=$True)]
[String]$UserName,
[Parameter(Mandatory=$False)]
[String]$Password,
[Parameter(Mandatory=$False)]
[String]$Metadata,
[Parameter(Mandatory=$False)]
[System.Byte[]]$Body,
[Parameter(Mandatory=$False)]
[String]$RequestDigest,
[Parameter(Mandatory=$False)]
[String]$ETag,
[Parameter(Mandatory=$False)]
[String]$XHTTPMethod,
[Parameter(Mandatory=$False)]
[System.String]$Accept = "application/json;odata=verbose",
[Parameter(Mandatory=$False)]
[String]$ContentType = "application/json;odata=verbose",
[Parameter(Mandatory=$False)]
[Boolean]$BinaryStringResponseBody = $False
)
if([string]::IsNullOrEmpty($Password)) {
$SecurePassword = Read-Host Prompt "Enter the password" AsSecureString
}
else {
$SecurePassword = $Password | ConvertTo-SecureString AsPlainText Force
}
$credentials = New-Object Microsoft.SharePoint.Client.SharePointOnlineCredentials($UserName, $SecurePassword)
$request = [System.Net.WebRequest]::Create($Url)
$request.Credentials = $credentials
$request.Headers.Add("X-FORMS_BASED_AUTH_ACCEPTED", "f")
$request.ContentType = $ContentType
$request.Accept = $Accept
$request.Method=$Method
if($RequestDigest) {
$request.Headers.Add("X-RequestDigest", $RequestDigest)
}
if($ETag) {
$request.Headers.Add("If-Match", $ETag)
}
if($XHTTPMethod) {
$request.Headers.Add("X-HTTP-Method", $XHTTPMethod)
}
if($Metadata -or $Body) {
if($Metadata) {
$Body = [byte[]][char[]]$Metadata
}
$request.ContentLength = $Body.Length
$stream = $request.GetRequestStream()
$stream.Write($Body, 0, $Body.Length)
}
else {
$request.ContentLength = 0
}
#Process Response
$response = $request.GetResponse()
try {
if($BinaryStringResponseBody -eq $False) {
$streamReader = New-Object System.IO.StreamReader $response.GetResponseStream()
try {
$data=$streamReader.ReadToEnd()
$results = $data | ConvertFrom-Json
$results.d
}
finally {
$streamReader.Dispose()
}
}
else {
$dataStream = New-Object System.IO.MemoryStream
try {
StreamCopyTo Source $response.GetResponseStream() Destination $dataStream
$dataStream.ToArray()
}
finally {
$dataStream.Dispose()
}
}
}
finally {
$response.Dispose()
}
}
# Get Context Info
Function Get-SPOContextInfo(){
Param(
[Parameter(Mandatory=$True)]
[String]$WebUrl,
[Parameter(Mandatory=$True)]
[String]$UserName,
[Parameter(Mandatory=$False)]
[String]$Password
)
$Url = $WebUrl + "/_api/contextinfo"
Invoke-RestSPO $Url Post $UserName $Password
}
Function Stream-CopyTo([System.IO.Stream]$Source, [System.IO.Stream]$Destination)
{
$buffer = New-Object Byte[] 8192
$bytesRead = 0
while (($bytesRead = $Source.Read($buffer, 0, $buffer.Length)) -gt 0)
{
$Destination.Write($buffer, 0, $bytesRead)
}
}

view raw
Invoke-RestSPO.ps1
hosted with ❤ by GitHub

Request Digests

Since SharePoint requires the user to include a request digest value with each create, update and delete operation, an additional request is invoked using Get-SPOContextInfo function to request Context Info entity that contains request digest value.

 ETag

In order to avoid an additional request, “*” eTag value is used to match any eTag value resulting in the operation being performed regardless of the actual value.

Lists manipulation using REST API in PowerShell

This section contains sample code for all of the CRUD operations.

#———————————————————————————————-
# List CRUD operations via SharePoint REST API
#———————————————————————————————-
# Create a List
Function New-SPOList(){
Param(
[Parameter(Mandatory=$True)]
[String]$WebUrl,
[Parameter(Mandatory=$True)]
[String]$UserName,
[Parameter(Mandatory=$False)]
[String]$Password,
[Parameter(Mandatory=$True)]
[String]$Title,
[Parameter(Mandatory=$True)]
[String]$BaseTemplate
)
$listMetadata = @{
__metadata = @{'type' = 'SP.List' };
Title = $Title;
BaseTemplate = $BaseTemplate} | ConvertTo-Json
$Url = $WebUrl + "/_api/lists"
$contextInfo = Get-SPOContextInfo $WebUrl $UserName $Password
Invoke-RestSPO $Url Post $UserName $Password $listMetadata $contextInfo.GetContextWebInformation.FormDigestValue
}
# Update a List
Function Set-SPOList(){
Param(
[Parameter(Mandatory=$True)]
[String]$WebUrl,
[Parameter(Mandatory=$True)]
[String]$UserName,
[Parameter(Mandatory=$False)]
[String]$Password,
[Parameter(Mandatory=$True)]
[String]$Identity,
[Parameter(Mandatory=$False)]
[String]$Title,
[Parameter(Mandatory=$False)]
[String]$Description
)
$listMetadata = @{
__metadata = @{'type' = 'SP.List' };
}
if($Title) {
$listMetadata['Title'] = $Title
}
if($Description) {
$listMetadata['Description'] = $Description
}
$listMetadata = $listMetadata | ConvertTo-Json
$Url = $WebUrl + "/_api/lists/getbytitle('" + $Identity + "')"
$contextInfo = Get-SPOContextInfo $WebUrl $UserName $Password
Invoke-RestSPO Url $Url Method Post UserName $UserName Password $Password RequestDigest $contextInfo.GetContextWebInformation.FormDigestValue Metadata $listMetadata ETag "*" XHTTPMethod "MERGE"
}
#Get List(s)
Function Get-SPOList(){
Param(
[Parameter(Mandatory=$True)]
[String]$WebUrl,
[Parameter(Mandatory=$True)]
[String]$UserName,
[Parameter(Mandatory=$False)]
[String]$Password
)
$Url = $WebUrl + "/_api/lists"
$data = Invoke-RestSPO $Url Get $UserName $Password
$data.results
}
#Delete a List
Function Remove-SPOList(){
Param(
[Parameter(Mandatory=$True)]
[String]$WebUrl,
[Parameter(Mandatory=$True)]
[String]$UserName,
[Parameter(Mandatory=$False)]
[String]$Password,
[Parameter(Mandatory=$True)]
[String]$Identity
)
$Url = $WebUrl + "/_api/lists/getbytitle('" + $Identity + "')"
$contextInfo = Get-SPOContextInfo $WebUrl $UserName $Password
Invoke-RestSPO Url $Url Method Post UserName $UserName Password $Password RequestDigest $contextInfo.GetContextWebInformation.FormDigestValue ETag "*" XHTTPMethod "DELETE"
}

view raw
ListOps-RestSPO.ps1
hosted with ❤ by GitHub

References

 

Working with the SharePoint Online REST service via PowerShell

Since SharePoint 2013 introduces a Representational State Transfer (REST) service that is comparable to the existing SharePoint client object models, it opens up a huge capabilities, in particular for administering and automating SharePoint Online when used with PowerShell.

My first idea was to utilize  Invoke-RestMethod cmdlet, which was introduced in Windows PowerShell 3.0.  Invoke-RestMethod cmdlet contains Credential parameter which could  accept basic, digest, NTLM, and Kerberos authentication.

SharePoint Client Component SDK comes with  a SharePointOnlineCredentials class  which represents an object that provides credentials to access SharePoint Online resources. But unfortunately SharePoint Online credentials could not be passed in Invoke-RestMethod cmdlet, since claims based authentication is not supported by this cmdlet.

Below is demonstrated a simplified PowerShell script  that to some extent mimics Invoke-RestMethod cmdlet. This script is intended for sending HTTPS request to a SharePoint Online REST service:

Param(
[Parameter(Mandatory=$True)]
[String]$Url,
[Parameter(Mandatory=$False)]
[Microsoft.PowerShell.Commands.WebRequestMethod]$Method = [Microsoft.PowerShell.Commands.WebRequestMethod]::Get,
[Parameter(Mandatory=$True)]
[String]$UserName,
[Parameter(Mandatory=$False)]
[String]$Password
)
Add-Type –Path "C:\Program Files\Common Files\microsoft shared\Web Server Extensions\15\ISAPI\Microsoft.SharePoint.Client.dll"
Add-Type –Path "C:\Program Files\Common Files\microsoft shared\Web Server Extensions\15\ISAPI\Microsoft.SharePoint.Client.Runtime.dll"
if([string]::IsNullOrEmpty($Password)) {
$SecurePassword = Read-Host Prompt "Enter the password" AsSecureString
}
else {
$SecurePassword = $Password | ConvertTo-SecureString AsPlainText Force
}
$credentials = New-Object Microsoft.SharePoint.Client.SharePointOnlineCredentials($UserName, $SecurePassword)
$request = [System.Net.WebRequest]::Create($Url)
$request.Credentials = $credentials
$request.Headers.Add("X-FORMS_BASED_AUTH_ACCEPTED", "f")
$request.Accept = "application/json;odata=verbose"
$request.Method=$Method
$response = $request.GetResponse()
$requestStream = $response.GetResponseStream()
$readStream = New-Object System.IO.StreamReader $requestStream
$data=$readStream.ReadToEnd()
$results = $data | ConvertFrom-Json
$results.d.results

view raw
Invoke-RestSPO.ps1
hosted with ❤ by GitHub

Examples

#Example 1. Gets a value that specifies usage information about the site, including bandwidth, storage, and the number of visits to the site collection
$result = .\Invoke-RestSPO.ps1 Url "https://contoso.sharepoint.com/_api/site/usage" UserName "username@tenant.onmicrosoft.com" Password "password"
write-host 'Total amount of disk space, currently being used by the site collection (Mb):' ([math]::round($result.Usage.Storage /1Mb))
#Example 2. Get List Items
.\Invoke-RestSPO.ps1 Url "https://contoso.sharepoint.com/_api/web/lists/getbytitle('Contacts&#39;)/title" UserName "username@tenatnt.onmicrosoft.com" Password "password"

References

Embedding and Sharing Video in SharePoint. Part Three: Aggregating Video Feeds and utilizing API

Introduction

Previous two posts were devoted to discussion of how to integrate video from YouTube and another Video Providers into SharePoint. In the first post we have discussed how to store embedded video properties and render YouTube player using Computed Field. In the second one we have discussed how to store embed code itself as it was generated by Provider.
This time we will discuss at how you can aggregate video from RSS/Atom Feeds and provide some information about using API for retrieving video content from Video Providers.

Aggregating from Video Providers RSS/Atom Feeds using YouTube

When you retrieve a video feed or list of search results, YouTube returns an Atom feed. Below is presented description of how to display videos from YouTube Feed, in our case we will display results from YouTube channel only.
For retrieving video content and displaying results  YouTube Viewer web part will be used here. In fact, it is just RSSAggregator web part, but with custom XSLT style sheet for processing YouTube feed, for details see implementation section.
So, let’s  see how to add video from YouTube feed on page:

  • Add YouTube Viewer web part which located under category Media Extensions on page
  • Specify FeedUrl for YouTube channel, for example to display video feed from Critical Path Training specify value as shown on picture
  • Result page with  YouTube web part configured is shown below

Utilizing Video Providers API

Another option to retrieve YouTube content  is to use .NET  or JavaScript client libraries directly in SharePoint.
The table below represents summary information about API for commonly used Video Providers listed in oEmbed.

Table 1. API support for Video Providers.

Provider Name API Description
YouTube Data API, Google Data client libraries for use the YouTube Data API (Java.NET, PHP, Python, Objective-C, JavaScript)
Viddler Viddler API
Qik Qik API, client for JavaScript
Vimeo Vimeo APIs

And for displaying it we need some logic to be implemented, for example by creating  custom web part. Implementation details for this functionality  are omitted here.

Implementation

For aggregating and rendering  YouTube Feeds RSSAggregator web part is used as was noted earlier with custom XSLT style sheet for processing YouTube Video Feeds.

To render YouTube feeds we provide custom  XSLT style sheet by specifying XslLink property

and the following XSLT style sheet

<xsl:stylesheet xmlns:x="http://www.w3.org/2001/XMLSchema"
version="1.0" exclude-result-prefixes="xsl ddwrt msxsl rssaggwrt"
xmlns:ddwrt="http://schemas.microsoft.com/WebParts/v2/DataView/runtime"
xmlns:rssaggwrt="http://schemas.microsoft.com/WebParts/v3/rssagg/runtime"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:msxsl="urn:schemas-microsoft-com:xslt"
xmlns:rssFeed="urn:schemas-microsoft-com:sharepoint:RSSAggregatorWebPart"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:rss1="http://purl.org/rss/1.0/" xmlns:atom="http://www.w3.org/2005/Atom"
xmlns:itunes="http://www.itunes.com/dtds/podcast-1.0.dtd"
xmlns:atom2="http://purl.org/atom/ns#" xmlns:ddwrt2="urn:frontpage:internal"
xmlns:media="http://search.yahoo.com/mrss/"
xmlns:yt="http://gdata.youtube.com/schemas/2007">
<xsl:param name="rss_FeedLimit">3</xsl:param>
<xsl:param name="rss_ExpandFeed">false</xsl:param>
<xsl:param name="rss_LCID">1033</xsl:param>
<xsl:param name="rss_WebPartID">RSS_Viewer_WebPart</xsl:param>
<xsl:param name="rss_alignValue">left</xsl:param>
<xsl:param name="rss_IsDesignMode">True</xsl:param>
<xsl:template match="atom:feed">
<link rel="stylesheet" Type="text/css" href="/_layouts/MediaExtensions/VideoLinks.css"/>
<xsl:call-template name="ATOMYouTubeTemplate"/>
</xsl:template>
<xsl:template name="ATOMYouTubeTemplate" xmlns:ddwrt="http://schemas.microsoft.com/WebParts/v2/DataView/runtime" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:msxsl="urn:schemas-microsoft-com:xslt">
<xsl:variable name="Rows" select="atom:entry"/>
<xsl:variable name="RowCount" select="count($Rows)"/>
<div class="channel-browse" >
<div class="channels-browse-gutter-padding" >
<ul class="channels-browse-content-grid context-data-container ">
<xsl:call-template name="ATOMYouTubeTemplate.body">
<xsl:with-param name="Rows" select="$Rows"/>
<xsl:with-param name="RowCount" select="count($Rows)"/>
</xsl:call-template>
</ul>
</div>
</div>
</xsl:template>
<xsl:template name="ATOMYouTubeTemplate.body" xmlns:ddwrt="http://schemas.microsoft.com/WebParts/v2/DataView/runtime" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:msxsl="urn:schemas-microsoft-com:xslt">
<xsl:param name="Rows"/>
<xsl:param name="RowCount"/>
<xsl:for-each select="$Rows">
<xsl:variable name="CurPosition" select="position()" />
<xsl:variable name="RssFeedLink" select="$rss_WebPartID" />
<xsl:variable name="CurrentElement" select="concat($RssFeedLink,$CurPosition)" />
<xsl:if test="($CurPosition &lt;= $rss_FeedLimit)">
<li class="channels-content-item">
<xsl:call-template name="ATOMYouTubeTemplate.contentitem">
<xsl:with-param name="CurrentElement" select="$CurrentElement"/>
</xsl:call-template>
</li>
</xsl:if>
</xsl:for-each>
</xsl:template>
<xsl:template name="ATOMYouTubeTemplate.contentitem" xmlns:ddwrt="http://schemas.microsoft.com/WebParts/v2/DataView/runtime" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:msxsl="urn:schemas-microsoft-com:xslt">
<xsl:param name="CurrentElement"/>
<span class="context-data-item">
<a onclick="javascript:window.open(this.href, 'YouTube', 'height=600,width=800,resizable');return false;" href="{ddwrt:EnsureAllowedProtocol(string(atom:link/@href))}" class="ux-thumb-wrap" >
<span class="video-thumb">
<span class="yt-thumb-clip">
<span class="yt-thumb-clip-inner">
<xsl:variable name="ThumbnailUrl" select="media:group/media:thumbnail[@width='120']/@url">
</xsl:variable>
<img src="{$ThumbnailUrl}" alt="Thumbnail" width="194" />
<span class="vertical-align"></span>
</span>
</span>
</span>
<span class="video-time">
<xsl:value-of select="media:group/yt:duration/@seconds" /> sec
</span>
</a>
<!–<a href="{ddwrt:EnsureAllowedProtocol(string(atom:link/@href))}" title="{string(atom:title)}" class="content-item-title spf-link" dir="ltr">–>
<a onclick="javascript:window.open(this.href, 'YouTube', 'height=600,width=800,resizable');return false;" href="{ddwrt:EnsureAllowedProtocol(string(atom:link/@href))}" title="{string(atom:title)}" class="content-item-title spf-link" dir="ltr">
<xsl:call-template name="GetSafeHtml">
<xsl:with-param name="Html" select="substring(atom:title, 1, 28)"/>
</xsl:call-template>…
</a>
<span class="content-item-detail">
<span class="content-item-view-count">
<xsl:value-of select="yt:statistics/@viewCount" /> views
</span>
<span class="metadata-separator">|</span>
<span class="content-item-time-created">
<xsl:value-of select="ddwrt:FormatDate(atom:published, 2057, 3)"/>
</span>
</span>
</span>
</xsl:template>
<xsl:template name="GetSafeHtml">
<xsl:param name="Html"/>
<xsl:choose>
<xsl:when test="$rss_IsDesignMode = 'True'">
<xsl:value-of select="$Html"/>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="rssaggwrt:MakeSafe($Html)"/>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>

view raw
YouTubeVideoFeed.xsl
hosted with ❤ by GitHub

References

Embedding and Sharing Video in SharePoint

Introduction

The solution described here allows to embed video hosted on YouTube into SharePoint. The same approach may be applied for embedding video from another video hosting sites, for example from Vimeo.

The main idea here to store embedded video properties and not the embedded code itself.
For storing embedded video properties we will use Custom  List, see implementation section for description. Page for Video Links list (default view with embedded player)  is shown below

Usage

In order to embed a video into SharePoint:

  • On YouTube site click the Share button located under the video.
  • Click the Embed button.
  • Copy at least src attribute value provided in the expanded box (see table 1 for supported attributes).

  • Create new Video Link item  and paste attribute values for embedded code into Video Links item. Save it.

Table 1. Mapping between embedded code iframe attributes and Video Link item

Attribute name Video Links field name
src URL
width Video Width
height Video Height
allowfullscreen Allow Fullscreen
frameborder Frame Border

Video Links implementation

As was mentioned earlier only properties for embedded video code are stored and not the embedded code itself. For storing embedded video code properties is used Custom List that extends OOB Links List (TemplateType = 103)

For embedded video properties we create Video Link Content Type that inherits from Link CT (0x0105)

where we define the following fields

<?xml version="1.0" encoding="utf-8"?>
<Elements xmlns="http://schemas.microsoft.com/sharepoint/">
<Field Type="Number"
DisplayName="Frame Border"
Required="FALSE"
EnforceUniqueValues="FALSE"
Group="Media Columns"
ID="{594e551f-180d-47ec-90e5-9195225c5932}"
StaticName="FrameBorder"
Name="FrameBorder"
Percentage="FALSE"
Hidden="FALSE"
SourceID="http://schemas.microsoft.com/sharepoint/v3">
<Default>0</Default>
</Field>
<Field Type="Number"
DisplayName="Video Height"
Required="FALSE"
EnforceUniqueValues="FALSE"
Group="Media Columns"
ID="{a1e94df1-eb6e-4fd2-aef7-bf0cc175c760}"
StaticName="VideoHeight"
Name="VideoHeight"
Percentage="FALSE"
Hidden="FALSE"
SourceID="http://schemas.microsoft.com/sharepoint/v3"/>
<Field Type="Number"
DisplayName="Video Width"
Required="FALSE"
EnforceUniqueValues="FALSE"
Group="Media Columns"
ID="{e0406eee-7432-47d8-9080-8c1c4db23170}"
StaticName="VideoWidth"
Name="VideoWidth"
Percentage="FALSE"
Hidden="FALSE"
SourceID="http://schemas.microsoft.com/sharepoint/v3"/>
<Field Type="Boolean"
DisplayName="Allow FullScreen"
EnforceUniqueValues="FALSE"
Group="Media Columns"
ID="{b6ba6c8f-81d6-478a-a303-3b18687ec934}"
StaticName="AllowFullScreen"
Name="AllowFullScreen"
Required="FALSE"
Hidden="FALSE"
SourceID="http://schemas.microsoft.com/sharepoint/v3">
<Default>0</Default>
</Field>
<Field Type="Choice"
DisplayName="Embedding Mode"
Required="FALSE"
EnforceUniqueValues="FALSE"
Format="Dropdown"
FillInChoice="FALSE"
Group="Media Columns"
ID="{5836ef4c-c440-4cb8-a471-0ee918bfc710}"
StaticName="EmbeddingMode"
Name="EmbeddingMode"
Hidden="FALSE"
SourceID="http://schemas.microsoft.com/sharepoint/v3">
<Default>IFrame</Default>
<CHOICES>
<CHOICE>IFrame</CHOICE>
<CHOICE>Object</CHOICE>
</CHOICES>
</Field>
<Field
ID="{C1D8C50A-2146-41f6-80CC-02C7691392A3}"
Type="Computed"
Name="EmbeddedVideoOnForm"
StaticName="EmbeddedVideoOnForm"
DisplaceOnUpgrade="TRUE"
ShowInNewForm="FALSE"
ShowInDisplayForm="FALSE"
ShowInEditForm="FALSE"
ShowInFileDlg="FALSE"
DisplayName="Embedded Video"
SourceID="http://schemas.microsoft.com/sharepoint/v3/fields"
Sealed="TRUE"
Sortable="FALSE"
Filterable="FALSE">
<FieldRefs>
<FieldRef Name="URL" />
<FieldRef Name="FileLeafRef" />
<FieldRef Name="FileRef" />
<FieldRef Name="FSObjType" />
<FieldRef Name="EmbeddingMode" />
<FieldRef Name="VideoWidth" />
<FieldRef Name="VideoHeight" />
<FieldRef Name="FrameBorder" />
</FieldRefs>
<DisplayPattern>
<IfEqual>
<Expr1>
<Column Name="EmbeddingMode" />
</Expr1>
<Expr2>IFrame</Expr2>
<Then>
<HTML><![CDATA[<iframe width=']]></HTML>
<Field Name="VideoWidth"/>
<HTML><![CDATA[' height=']]></HTML>
<Field Name="VideoHeight"/>
<HTML><![CDATA[' src=']]></HTML>
<Field Name="URL"/>
<HTML><![CDATA[' frameborder=']]></HTML>
<Field Name="FrameBorder"/>
<HTML><![CDATA[' allowfullscreen']]></HTML>
<HTML>
<![CDATA['></iframe>]]>
</HTML>
</Then>
<Else>
<HTML>
<![CDATA[Not supported yet]]>
</HTML>
</Else>
</IfEqual>
</DisplayPattern>
</Field>
</Elements>

Pay attention, for rendering YouTube player Computed Field EmbeddedVideoOnForm is intended.
For rendering of a field on a List View the following XSLT style sheet is used

And finally, we create List Definition Video Links from Content Type Video Link. List schema and Template files for Video Links including whole project  may be found on GitHub.

References

  • Video Links project on GitHub
  • How to embed Vimeo player see here
  • How to embed YouTube player  see here
  • How to customize the rendering of a field in List View see here

Rendering Content Query Web Part results in Table Layout

It is known that OOB Content Query Web Part (CQWP)  renders results using Lists for arranging items as shown below

In ASP.NET WebForms for Web Control DataList there is a possibility to specify layout rendering mode using property RepeatLayout, what if the similar functionality would be available in CQWP?

So, our  goal to extend CQWP, i.e. in addition to List Layout rendering mode, lets implement functionality for rendering Content Query Web Part results in Plain Old Table Layout.
In this approach, we would like to achieve the following options:

  • Possibility to easily arrange results in columns
  • Specify items direction (horizontal or vertical)

Solution Structure

Content Query Web Part Class

using System;
using System.ComponentModel;
using System.Security.Permissions;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using Microsoft.SharePoint.Publishing.WebControls;
using Microsoft.SharePoint.Security;
using Microsoft.SharePoint.WebPartPages;
namespace CQWPWithTableLayout.WebControls
{
[ToolboxItem(false)]
public class CBQTableLayout : ContentByQueryWebPart
{
#region Control Lifecycle
protected override void CreateChildControls()
{
try
{
base.CreateChildControls();
}
catch (Exception ex)
{
throw;
}
}
protected override void ModifyXsltArgumentList(ArgumentClassWrapper argList)
{
argList.AddParameter("RepeatDirection", string.Empty, RepeatDirection);
argList.AddParameter("RepeatColumns", string.Empty, RepeatColumns);
base.ModifyXsltArgumentList(argList);
}
/// <summary>
/// Return the tool panes that configure this <see cref="T:Microsoft.SharePoint.Publishing.WebControls.ContentByQueryWebPart"/> object..
/// </summary>
[SharePointPermission(SecurityAction.Demand, ObjectModel = true)]
public override ToolPart[] GetToolParts()
{
return new ToolPart[3]
{
new ContentByQueryToolPart(),
new WebPartToolPart(),
new CBQTableLayoutToolPart()
};
}
#endregion
#region Properties
[Category("TableLayout")]
[Personalizable(PersonalizationScope.Shared), DefaultValue(3), WebBrowsable(true)]
public int RepeatColumns { get; set; }
[Category("TableLayout")]
[Personalizable(PersonalizationScope.Shared), DefaultValue(RepeatDirection.Horizontal), WebBrowsable(true)]
public RepeatDirection RepeatDirection { get; set; }
#endregion
}
}

Tool Part Class Implementation with the ability to specify Table Layout properties

using System;
using System.Globalization;
using System.Web.UI.WebControls;
namespace CQWPWithTableLayout.WebControls
{
public class CBQTableLayoutToolPart : Microsoft.SharePoint.WebPartPages.ToolPart
{
public CBQTableLayoutToolPart()
{
Init += InitToolPart;
}
private void InitToolPart(object sender, EventArgs e)
{
Title = "Table Layout Settings";
_targetWebPart = ParentToolPane.SelectedWebPart as CBQTableLayout;
if (_targetWebPart == null)
throw new Exception("Wrong web part type error");
}
protected override void CreateChildControls()
{
CreateTableLayoutSection();
PopulateTableLayoutSection();
base.CreateChildControls();
}
public override void ApplyChanges()
{
this.ApplySettingsSectionChanges();
base.ApplyChanges();
}
private void CreateTableLayoutSection()
{
_columnsBox = new TextBox {MaxLength = 2};
_directionBox = new DropDownList();
var mainTable = new Table { CellPadding = 2, CellSpacing = 2 };
mainTable.Style["border-collapse"] = "collapse";
//Repeat Columns
AddRepeatColumnsProperty(mainTable);
//Repeat Direction
AddRepeatDirectionProperty(mainTable);
Controls.Add(mainTable);
}
private void AddRepeatColumnsProperty(Table section)
{
var rowHeader = new TableRow();
var cellHeader = new TableCell { Text = "Repeat Columns" };
rowHeader.Cells.Add(cellHeader);
section.Rows.Add(rowHeader);
var rowItem = new TableRow();
var cellItem = new TableCell();
cellItem.Controls.Add(_columnsBox);
rowItem.Cells.Add(cellItem);
section.Rows.Add(rowItem);
}
private void AddRepeatDirectionProperty(Table section)
{
var rowHeader = new TableRow();
var cellHeader = new TableCell { Text = "Repeat Direction" };
rowHeader.Cells.Add(cellHeader);
section.Rows.Add(rowHeader);
var rowItem = new TableRow();
var cellItem = new TableCell();
cellItem.Controls.Add(_directionBox);
rowItem.Cells.Add(cellItem);
section.Rows.Add(rowItem);
}
private void PopulateTableLayoutSection()
{
_columnsBox.Text = _targetWebPart.RepeatColumns.ToString(CultureInfo.InvariantCulture);
var directions = Enum.GetValues(typeof(RepeatDirection));
_directionBox.DataSource = directions;
_directionBox.DataBind();
_directionBox.Text = _targetWebPart.RepeatDirection.ToString();
}
protected void ApplySettingsSectionChanges()
{
_targetWebPart.RepeatColumns = int.Parse(_columnsBox.Text);
_targetWebPart.RepeatDirection = (RepeatDirection)Enum.Parse(typeof(RepeatDirection), _directionBox.Text);
}
private TextBox _columnsBox;
private DropDownList _directionBox;
private CBQTableLayout _targetWebPart;
}
}

Web Part manifest file

<?xml version="1.0" encoding="utf-8"?>
<webParts>
<webPart xmlns="http://schemas.microsoft.com/WebPart/v3">
<metaData>
<type name="CQWPWithTableLayout.WebControls.CBQTableLayout, CQWPWithTableLayout, Version=1.0.0.0, Culture=neutral, PublicKeyToken=f96554baea0809a2" />
<importErrorMessage>Cannot import this Web Part.</importErrorMessage>
</metaData>
<data>
<properties>
<property name="Title" type="string">Content Query (Plain Old Table Layout)</property>
<property name="Description" type="string">Displays a dynamic view of content from your site.</property>
<property name="ChromeType">TitleOnly</property>
<property name="ChromeState">Normal</property>
<property name="ItemLimit" type="int">15</property>
<property name="SortBy" type="string">{8c06beca-0777-48f7-91c7-6da68bc07b69}</property>
<property name="SortByDirection" type="Microsoft.SharePoint.Publishing.WebControls.ContentByQueryWebPart+SortDirection,Microsoft.SharePoint.Publishing,Version=14.0.0.0,Culture=neutral,PublicKeyToken=71e9bce111e9429c">Desc</property>
<property name="GroupStyle" type="string">DefaultHeader</property>
<property name="ItemStyle" type="string">Default</property>
<property name="ServerTemplate" type="string"></property>
<property name="MainXslLink" type="string" >/Style Library/XSL Style Sheets/ContentQueryMainTableLayout.xsl</property>
<property name="RepeatColumns" type="int">0</property>
<property name="RepeatDirection" type="System.Web.UI.WebControls.RepeatDirection, System.Web, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">Vertical</property>
</properties>
</data>
</webPart>
</webParts>

Pay attention that we provide custom XSLT for processing of the CQWP, for more details see How to: Customize XSL for the SharePoint Content By Query Web Part.

Main XSLT style sheet for rendering results in Table Layout

<xsl:stylesheet
version="1.0"
exclude-result-prefixes="x xsl cmswrt cbq"
xmlns:x="http://www.w3.org/2001/XMLSchema"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:cmswrt="http://schemas.microsoft.com/WebPart/v3/Publishing/runtime"
xmlns:cbq="urn:schemas-microsoft-com:ContentByQueryWebPart">
<xsl:output method="xml" indent="no" media-type="text/html" omit-xml-declaration="yes"/>
<xsl:param name="cbq_isgrouping" />
<xsl:param name="cbq_columnwidth" />
<xsl:param name="Group" />
<xsl:param name="GroupType" />
<xsl:param name="cbq_iseditmode" />
<xsl:param name="cbq_viewemptytext" />
<xsl:param name="cbq_errortext" />
<xsl:param name="SiteId" />
<xsl:param name="WebUrl" />
<xsl:param name="PageId" />
<xsl:param name="WebPartId" />
<xsl:param name="FeedPageUrl" />
<xsl:param name="FeedEnabled" />
<xsl:param name="SiteUrl" />
<xsl:param name="BlankTitle" />
<xsl:param name="BlankGroup" />
<xsl:param name="UseCopyUtil" />
<xsl:param name="DataColumnTypes" />
<xsl:param name="ClientId" />
<xsl:param name="Source" />
<xsl:param name="RootSiteRef" />
<xsl:param name="CBQPageUrl" />
<xsl:param name="CBQPageUrlQueryStringForFilters" />
<xsl:param name="RepeatDirection" />
<xsl:param name="RepeatColumns" />
<xsl:variable name="BeginTable" select="string('&lt;table class=&quot;dfwp-list&quot;&gt;')" />
<xsl:variable name="EndTable" select="string('&lt;/table&gt;')" />
<xsl:variable name="BeginTableRow" select="string('&lt;tr&gt;')" />
<xsl:variable name="EndTableRow" select="string('&lt;/tr&gt;')" />
<xsl:variable name="BeginTableCell" select="string('&lt;td class=&quot;dfwp-item&quot;&gt;')" />
<xsl:variable name="EndTableCell" select="string('&lt;/td&gt;')" />
<xsl:template match="/">
<xsl:call-template name="OuterTemplate" />
</xsl:template>
<xsl:template name="OuterTemplate">
<xsl:variable name="Rows" select="/dsQueryResponse/Rows/Row" />
<xsl:variable name="RowCount" select="count($Rows)" />
<xsl:variable name="IsEmpty" select="$RowCount = 0" />
<div id="{concat('cbqwp', $ClientId)}" class="cbq-layout-main">
<xsl:if test="$cbq_iseditmode = 'True' and string-length($cbq_errortext) != 0">
<div class="wp-content description">
<xsl:value-of disable-output-escaping="yes" select="$cbq_errortext" />
</div>
</xsl:if>
<xsl:choose>
<xsl:when test="$IsEmpty">
<xsl:call-template name="OuterTemplate.Empty" >
<xsl:with-param name="EditMode" select="$cbq_iseditmode" />
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<xsl:call-template name="OuterTemplate.Body">
<xsl:with-param name="Rows" select="$Rows" />
<xsl:with-param name="FirstRow" select="1" />
<xsl:with-param name="LastRow" select="$RowCount" />
</xsl:call-template>
</xsl:otherwise>
</xsl:choose>
</div>
<xsl:if test="$FeedEnabled = 'True' and $PageId != ''">
<div class="cqfeed">
<xsl:variable name="FeedUrl1" select="concat($SiteUrl,$FeedPageUrl,'xsl=1&amp;web=',$WebUrl,'&amp;page=',$PageId,'&amp;wp=',$WebPartId,'&amp;pageurl=',$CBQPageUrl,$CBQPageUrlQueryStringForFilters)" />
<a href="{cmswrt:RegisterFeedUrl( $FeedUrl1, 'application/rss+xml')}">
<img src="\_layouts\images\rss.gif" border="0" alt="{cmswrt:GetPublishingResource('CbqRssAlt')}"/>
</a>
</div>
</xsl:if>
</xsl:template>
<xsl:template name="OuterTemplate.Empty">
<xsl:param name="EditMode" />
<xsl:if test="$EditMode = 'True' and string-length($cbq_errortext) = 0">
<div class="wp-content description">
<xsl:value-of disable-output-escaping="yes" select="$cbq_viewemptytext" />
</div>
</xsl:if>
</xsl:template>
<xsl:template name="OuterTemplate.Body">
<xsl:param name="Rows" />
<xsl:param name="FirstRow" />
<xsl:param name="LastRow" />
<xsl:value-of disable-output-escaping="yes" select="$BeginTable" />
<xsl:choose>
<xsl:when test="$RepeatDirection = 1">
<xsl:call-template name="OuterTemplate.CallVerticalLayoutTemplate">
<xsl:with-param name="Rows" select="$Rows" />
<xsl:with-param name="FirstRow" select="$FirstRow" />
<xsl:with-param name="LastRow" select="$LastRow" />
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<xsl:for-each select="$Rows">
<xsl:variable name="CurPosition" select="position()" />
<xsl:call-template name="OuterTemplate.CallHorizontalLayoutTemplate">
<xsl:with-param name="CurPosition" select="$CurPosition" />
<xsl:with-param name="LastRow" select="$LastRow" />
</xsl:call-template>
</xsl:for-each>
</xsl:otherwise>
</xsl:choose>
<xsl:value-of disable-output-escaping="yes" select="$EndTable" />
</xsl:template>
<xsl:template name="OuterTemplate.CallVerticalContainerTemplate">
<xsl:param name="RowPosition" />
<xsl:param name="RowsCount" />
<xsl:param name="ColsCount" />
<xsl:if test="$RowPosition &lt;= $RowsCount">
<xsl:value-of disable-output-escaping="yes" select="$BeginTableRow" />
<xsl:variable name="CurPosition" select="$RowPosition" />
<xsl:variable name="AllRows" select="/dsQueryResponse/Rows/Row" />
<xsl:for-each select="$AllRows">
<xsl:variable name="ColPosition" select="position()" />
<xsl:choose>
<xsl:when test="$ColPosition != 1 and $ColPosition &lt;= $ColsCount">
<xsl:variable name="CurPositionAbs" select="$CurPosition + $RowsCount * ($ColPosition – 1)" />
<xsl:if test="$CurPositionAbs &lt;= (count($AllRows))">
<xsl:call-template name="OuterTemplate.CallItemTemplate">
<xsl:with-param name="CurPosition" select="$CurPositionAbs" />
</xsl:call-template>
</xsl:if>
</xsl:when>
<xsl:otherwise>
<xsl:if test="$ColPosition &lt;= $ColsCount">
<xsl:call-template name="OuterTemplate.CallItemTemplate">
<xsl:with-param name="CurPosition" select="$RowPosition" />
</xsl:call-template>
</xsl:if>
</xsl:otherwise>
</xsl:choose>
</xsl:for-each>
<xsl:value-of disable-output-escaping="yes" select="$EndTableRow" />
</xsl:if>
<xsl:if test="$RowPosition &lt;= $RowsCount">
<xsl:call-template name="OuterTemplate.CallVerticalContainerTemplate">
<xsl:with-param name="RowPosition">
<xsl:value-of select="$RowPosition + 1"/>
</xsl:with-param>
<xsl:with-param name="RowsCount">
<xsl:value-of select="$RowsCount"/>
</xsl:with-param>
<xsl:with-param name="ColsCount">
<xsl:value-of select="$ColsCount"/>
</xsl:with-param>
</xsl:call-template>
</xsl:if>
</xsl:template>
<xsl:template name="OuterTemplate.CallHeaderTemplate">
<xsl:apply-templates select="." mode="header">
</xsl:apply-templates>
</xsl:template>
<xsl:template name="OuterTemplate.CallVerticalLayoutTemplate">
<xsl:param name="Rows" />
<xsl:param name="FirstRow" />
<xsl:param name="LastRow" />
<!–Calc Cols & Rows–>
<xsl:choose>
<xsl:when test="$RepeatColumns = 0 or $RepeatColumns = 1">
<xsl:variable name="ColsCount" select="1" />
<xsl:variable name="RowsCount" select="$LastRow" />
<xsl:call-template name="OuterTemplate.CallVerticalContainerTemplate">
<xsl:with-param name="RowPosition" select="1" />
<xsl:with-param name="RowsCount" select="$RowsCount" />
<xsl:with-param name="ColsCount" select="$ColsCount" />
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<xsl:variable name="ColsCount" select="$RepeatColumns" />
<xsl:variable name="RowsCount" select="floor(($LastRow + $RepeatColumns – 1) div $RepeatColumns)" />
<xsl:call-template name="OuterTemplate.CallVerticalContainerTemplate">
<xsl:with-param name="RowPosition" select="1" />
<xsl:with-param name="RowsCount" select="$RowsCount" />
<xsl:with-param name="ColsCount" select="$ColsCount" />
</xsl:call-template>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<xsl:template name="OuterTemplate.CallHorizontalLayoutTemplate">
<xsl:param name="CurPosition" />
<xsl:param name="LastRow" />
<xsl:choose>
<xsl:when test="$RepeatColumns = 0">
<xsl:if test="$CurPosition = 1">
<xsl:value-of disable-output-escaping="yes" select="$BeginTableRow" />
</xsl:if>
</xsl:when>
<xsl:otherwise>
<xsl:if test="$CurPosition mod $RepeatColumns = 1">
<xsl:value-of disable-output-escaping="yes" select="$BeginTableRow" />
</xsl:if>
</xsl:otherwise>
</xsl:choose>
<xsl:call-template name="OuterTemplate.CallItemTemplate">
<xsl:with-param name="CurPosition" select="$CurPosition" />
</xsl:call-template>
<xsl:choose>
<xsl:when test="$RepeatColumns = 0">
<xsl:if test="$CurPosition = $LastRow">
<xsl:value-of disable-output-escaping="yes" select="$EndTableRow" />
</xsl:if>
</xsl:when>
<xsl:otherwise>
<xsl:if test="$CurPosition mod $RepeatColumns = 0">
<xsl:value-of disable-output-escaping="yes" select="$EndTableRow" />
</xsl:if>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<xsl:template name="OuterTemplate.CallItemTemplateDummy">
<xsl:param name="CurPosition" />
<xsl:value-of disable-output-escaping="yes" select="$BeginTableCell" />
<xsl:value-of disable-output-escaping="yes" select="$CurPosition" />
<xsl:value-of disable-output-escaping="yes" select="$EndTableCell" />
</xsl:template>
<xsl:template name="OuterTemplate.CallItemTemplate">
<xsl:param name="CurPosition" />
<xsl:value-of disable-output-escaping="yes" select="$BeginTableCell" />
<xsl:choose>
<xsl:when test="@Style='NewsRollUpItem'">
<xsl:apply-templates select="." mode="itemstyle">
<xsl:with-param name="EditMode" select="$cbq_iseditmode" />
</xsl:apply-templates>
</xsl:when>
<xsl:when test="@Style='NewsBigItem'">
<xsl:apply-templates select="." mode="itemstyle">
<xsl:with-param name="CurPos" select="$CurPosition" />
</xsl:apply-templates>
</xsl:when>
<xsl:when test="@Style='NewsCategoryItem'">
<xsl:apply-templates select="." mode="itemstyle">
<xsl:with-param name="CurPos" select="$CurPosition" />
</xsl:apply-templates>
</xsl:when>
<xsl:otherwise>
<xsl:apply-templates select="/dsQueryResponse/Rows/Row[position() = $CurPosition]" mode="itemstyle">
</xsl:apply-templates>
<!–<xsl:value-of disable-output-escaping="yes" select="$CurPosition" />–>
</xsl:otherwise>
</xsl:choose>
<xsl:value-of disable-output-escaping="yes" select="$EndTableCell" />
</xsl:template>
<xsl:template name="OuterTemplate.CallFooterTemplate">
</xsl:template>
<xsl:template name="OuterTemplate.GetSafeLink">
<xsl:param name="UrlColumnName"/>
<xsl:if test="$UseCopyUtil = 'True'">
<xsl:value-of select="concat($RootSiteRef,'/_layouts/CopyUtil.aspx?Use=id&amp;Action=dispform&amp;ItemId=',@ID,'&amp;ListId=',@ListId,'&amp;WebId=',@WebId,'&amp;SiteId=',$SiteId,'&amp;Source=',$Source)"/>
</xsl:if>
<xsl:if test="$UseCopyUtil != 'True'">
<xsl:call-template name="OuterTemplate.GetSafeStaticUrl">
<xsl:with-param name="UrlColumnName" select="$UrlColumnName"/>
</xsl:call-template>
</xsl:if>
</xsl:template>
<xsl:template name="OuterTemplate.GetTitle">
<xsl:param name="Title"/>
<xsl:param name="UrlColumnName"/>
<xsl:param name="UseFileName" select="0"/>
<xsl:choose>
<xsl:when test="string-length($Title) != 0 and $UseFileName = 0">
<xsl:value-of select="$Title" />
</xsl:when>
<xsl:when test="$UseCopyUtil = 'True' and $UseFileName = 0">
<xsl:value-of select="$BlankTitle" />
</xsl:when>
<xsl:otherwise>
<xsl:variable name="FileNameWithExtension">
<xsl:call-template name="OuterTemplate.GetPageNameFromUrl">
<xsl:with-param name="UrlColumnName" select="$UrlColumnName" />
</xsl:call-template>
</xsl:variable>
<xsl:choose>
<xsl:when test="$UseFileName = 1">
<xsl:call-template name="OuterTemplate.GetFileNameWithoutExtension">
<xsl:with-param name="input" select="$FileNameWithExtension" />
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$FileNameWithExtension" />
</xsl:otherwise>
</xsl:choose>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<xsl:template name="OuterTemplate.FormatColumnIntoUrl">
<xsl:param name="UrlColumnName"/>
<xsl:variable name="Value" select="@*[name()=$UrlColumnName]"/>
<xsl:if test="contains($DataColumnTypes,concat(';',$UrlColumnName,',URL;'))">
<xsl:call-template name="OuterTemplate.FormatValueIntoUrl">
<xsl:with-param name="Value" select="$Value"/>
</xsl:call-template>
</xsl:if>
<xsl:if test="not(contains($DataColumnTypes,concat(';',$UrlColumnName,',URL;')))">
<xsl:value-of select="$Value"/>
</xsl:if>
</xsl:template>
<xsl:template name="OuterTemplate.FormatValueIntoUrl">
<xsl:param name="Value"/>
<xsl:if test="not(contains($Value,', '))">
<xsl:value-of select="$Value"/>
</xsl:if>
<xsl:if test="contains($Value,', ')">
<xsl:call-template name="OuterTemplate.Replace">
<xsl:with-param name="Value" select="substring-before($Value,', ')"/>
<xsl:with-param name="Search" select="',,'"/>
<xsl:with-param name="Replace" select="','"/>
</xsl:call-template>
</xsl:if>
</xsl:template>
<xsl:template name="OuterTemplate.Replace">
<xsl:param name="Value"/>
<xsl:param name="Search"/>
<xsl:param name="Replace"/>
<xsl:if test="contains($Value,$Search)">
<xsl:value-of select="concat(substring-before($Value,$Search),$Replace)"/>
<xsl:call-template name="OuterTemplate.Replace">
<xsl:with-param name="Value" select="substring-after($Value,$Search)"/>
<xsl:with-param name="Search" select="$Search"/>
<xsl:with-param name="Replace" select="$Replace"/>
</xsl:call-template>
</xsl:if>
<xsl:if test="not(contains($Value,$Search))">
<xsl:value-of select="$Value"/>
</xsl:if>
</xsl:template>
<xsl:template name="OuterTemplate.GetSafeStaticUrl">
<xsl:param name="UrlColumnName"/>
<xsl:variable name="Url">
<xsl:call-template name="OuterTemplate.FormatColumnIntoUrl">
<xsl:with-param name="UrlColumnName" select="$UrlColumnName"/>
</xsl:call-template>
</xsl:variable>
<xsl:value-of select="cmswrt:EnsureIsAllowedProtocol($Url)"/>
</xsl:template>
<xsl:template name="OuterTemplate.GetColumnDataForUnescapedOutput">
<xsl:param name="Name"/>
<xsl:param name="MustBeOfType"/>
<xsl:if test="contains($DataColumnTypes,concat(';',$Name,',',$MustBeOfType,';'))">
<xsl:value-of select="@*[name()=$Name]"/>
</xsl:if>
</xsl:template>
<xsl:template name="OuterTemplate.GetPageNameFromUrl">
<xsl:param name="UrlColumnName"/>
<xsl:variable name="Url">
<xsl:call-template name="OuterTemplate.FormatColumnIntoUrl">
<xsl:with-param name="UrlColumnName" select="$UrlColumnName"/>
</xsl:call-template>
</xsl:variable>
<xsl:call-template name="OuterTemplate.GetPageNameFromUrlRecursive">
<xsl:with-param name="Url" select="$Url"/>
</xsl:call-template>
</xsl:template>
<xsl:template name="OuterTemplate.GetPageNameFromUrlRecursive">
<xsl:param name="Url"/>
<xsl:choose>
<xsl:when test="contains($Url,'/') and substring($Url,string-length($Url)) != '/'">
<xsl:call-template name="OuterTemplate.GetPageNameFromUrlRecursive">
<xsl:with-param name="Url" select="substring-after($Url,'/')"/>
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$Url"/>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<xsl:template name="OuterTemplate.GetGroupName">
<xsl:param name="GroupName"/>
<xsl:param name="GroupType"/>
<xsl:choose>
<xsl:when test="string-length(normalize-space($GroupName)) = 0">
<xsl:value-of select="$BlankGroup"/>
</xsl:when>
<xsl:otherwise>
<xsl:choose>
<xsl:when test="$GroupType='URL'">
<xsl:variable name="Url">
<xsl:call-template name="OuterTemplate.FormatValueIntoUrl">
<xsl:with-param name="Value" select="$GroupName"/>
</xsl:call-template>
</xsl:variable>
<xsl:call-template name="OuterTemplate.GetPageNameFromUrlRecursive">
<xsl:with-param name="Url" select="$Url"/>
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$GroupName" />
</xsl:otherwise>
</xsl:choose>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<xsl:template name="OuterTemplate.CallPresenceStatusIconTemplate">
<xsl:if test="string-length(@SipAddress) != 0">
<span class="presence-status-icon">
<img src="/_layouts/images/imnhdr.gif" onload="IMNRC('{@SipAddress}')" ShowOfflinePawn="1" alt="" id="{concat('MWP_pawn_',$ClientId,'_',@ID,'type=sip')}"/>
</span>
</xsl:if>
</xsl:template>
<xsl:template name="OuterTemplate.GetFileNameWithoutExtension">
<xsl:param name="input"/>
<xsl:variable name="extension">
<xsl:value-of select="substring-after($input, '.')"/>
</xsl:variable>
<xsl:choose>
<xsl:when test="contains($extension, '.')">
<xsl:variable name="afterextension">
<xsl:call-template name="OuterTemplate.GetFileNameWithoutExtension">
<xsl:with-param name="input" select="$extension"/>
</xsl:call-template>
</xsl:variable>
<xsl:value-of select="concat(substring-before($input, '.'), $afterextension)"/>
</xsl:when>
<xsl:otherwise>
<xsl:choose>
<xsl:when test="contains($input, '.')">
<xsl:value-of select="substring-before($input, '.')"/>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$input"/>
</xsl:otherwise>
</xsl:choose>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>

Results

Below is shown Web Part configured  to display results in 4 columns and horizontal mode layout

CBQTableLayoutHorizontal2

Visualizing organizational structure in SharePoint with Google Chart Tools

Sometimes in SharePoint we need to visualize hierarchical  data as organizational chart. Prerequisites: not to use  Flash or Silverlight technologies here.

So, in our scenario for storage of organization structure will be used SharePoint List based on Custom List , for rendering engine  Google Chart Tools.

Implementation

First, let’s take a look at list’s schema for storing organizational structure

Name Type Description
ParentOrgElement Lookup Used for parent/child relationship
OrgDescription Note Display text for chart box
OrgAdditionalProperties Note Visual behavior for chart box

From Google Charts library we’ll use Organizational Chart package only.

1. Google Charts Tools loading and package initialization

function visualizeOrgChart(orgChartProperties) {
google.load('visualization', '1', { packages: ['orgchart'] });
google.OrgChartData = orgChartProperties;
google.setOnLoadCallback(loadOrgChart);
}

view raw
visualizeOrgChart.js
hosted with ❤ by GitHub

2. Fetch data using SharePoint Web Service from list that contains organizational structure

function loadOrgChart() {
var soapEnv =
"<soapenv:Envelope xmlns:soapenv='http://schemas.xmlsoap.org/soap/envelope/'&gt; \
<soapenv:Body> \
<GetListItems xmlns='http://schemas.microsoft.com/sharepoint/soap/'&gt; \
<listName>" + google.OrgChartData.ListName + "</listName> \
<viewFields> \
<ViewFields> \
<FieldRef Name='" + google.OrgChartData.TitleFieldName + "' /> \
<FieldRef Name='" + google.OrgChartData.TooltipFieldName + "' /> \
<FieldRef Name='" + google.OrgChartData.ParentFieldName + "' /> \
<FieldRef Name='" + google.OrgChartData.StyleFieldName + "' /> \
</ViewFields> \
</viewFields> \
</GetListItems> \
</soapenv:Body> \
</soapenv:Envelope>";
$.ajax({
url: L_Menu_BaseUrl + "/_vti_bin/lists.asmx",
type: "POST",
dataType: "xml",
data: soapEnv,
complete: onOrgChartDataLoaded,
contentType: "text/xml; charset=\"utf-8\""
});
}

view raw
loadOrgChart.js
hosted with ❤ by GitHub

3. Bind data source and draw chart

function onOrgChartDataLoaded(orgChartData, status) {
var data = new google.visualization.DataTable();
data.addColumn('string', 'Name');
data.addColumn('string', 'Parent');
data.addColumn('string', 'ToolTip');
var chartFieldNames = { Title: generateOwsFieldName(google.OrgChartData.TitleFieldName),
Tooltip: generateOwsFieldName(google.OrgChartData.TooltipFieldName),
Parent: generateOwsFieldName(google.OrgChartData.ParentFieldName),
Properties: generateOwsFieldName(google.OrgChartData.StyleFieldName)
};
var orgChartRowProperties = {};
var orgChartDataRows = [];
var orgChartResult = ($.browser.msie ? orgChartData.responseXML : orgChartData.responseText);
$(orgChartResult).find("z\\:row").each(function (rowIndex) {
var orgChartRow = [];
//if ($(this).attr(chartFieldNames.Layout) == undefined)
orgChartRow[0] = $(this).attr(chartFieldNames.Title);
//else {
// orgChartRow[0] = { v: $(this).attr(chartFieldNames.Title), f: $(this).attr(chartFieldNames.Layout) };
//}
orgChartRow[1] = ($(this).attr(chartFieldNames.Parent) != undefined ? $(this).attr(chartFieldNames.Parent).split(';#')[1] : '');
orgChartRow[2] = $(this).attr(chartFieldNames.Tooltip);
if ($(this).attr(chartFieldNames.Properties) != undefined) {
orgChartRowProperties[rowIndex] = parseChartRowProperties($(this).attr(chartFieldNames.Properties));
}
orgChartDataRows[orgChartDataRows.length] = orgChartRow;
});
data.addRows(orgChartDataRows);
$.each(orgChartRowProperties, function (rowIndex, rowProperty) {
data.setRowProperties(parseInt(rowIndex), rowProperty);
});
var chart = new google.visualization.OrgChart(document.getElementById('orgChartCanvas'));
chart.draw(data, { allowHtml: true, allowCollapse: true });
}

Usage

Result page with Org Structure rendered as Chart in List View

 

Designing and deployment of Context Data in Nintex Workflow

Context Data in Nintex Workflow represent values specific to the workflow, the context of the item and the current task within the workflow. As an example below are some of them

Initiator: The username (domain\username) who caused the item to be entered into the workflow

Item URL: The URL of the item in workflow

The complete list of Contex Data items and how to manage it is described  in Nintex Workflow User Manual.

Designing custom Context Data usually include the implementation of specific handler(class). In Nintex Workflow API  for this purposes exist class ContextDataItemBase, from which all Context Data items usually inherits.

The implementation of Context Data for returning approvers comments in XML format is presented below

/// <summary>
/// Context DataItem for All Approvers in Xml format
/// </summary>
public class AllApproverCommentsXml : ContextDataItemBase
{
/// <summary>
///
/// </summary>
/// <param name="ctx"></param>
/// <returns></returns>
public override object GetValueObject(NWWorkflowContext ctx)
{
return GetLastApproverCommentsAsXml(ctx);
}
internal string GetLastApproverCommentsAsXml(NWWorkflowContext ctx)
{
return new NintexTaskCollection(ctx.InstanceID, ctx.Web).GetAllApprovalTaskCommentsAsXml();
}
/// <summary>
/// Internal Name
/// </summary>
public override string InternalName
{
get { return "AllApproverCommentsXml"; }
}
}

Below is shown page for managing Context Data with custom Context Data added  and Insert Reference dialog that demonstrates the usage of custom Context Data when designing workflow   

Now our goal to automate the deployment of Context Data. For example, it is possible to create Data Context item during feature activation. For this task we’ll use method of class CustomCommonDataCollection (in namespace:Nintex.Workflow) from Nintex Workflow API:

public static void Add(string typeName, string assemblyName, string displayName, string description)

Adding Context Data item  in Nintex Workflow Management (shown below)

is equivalent to calling

CustomCommonDataCollection.Add(
"SharePoint.NW2010.Deployment.ContextDataItems.AllApproverCommentsXml",
"SharePoint.NW2010.Deployment, Version=1.0.0.0, Culture=neutral, PublicKeyToken=b6acd7f49f7aeb64",
"Approver Comments (XML)",
"Approver comments in XML format");

You could grab the source code for the project that demonstrates how to provision Context Data here.

Automating deployment of reusable workflows in Nintex Workflow 2010

One of the options for creating workflows in Nintex Workflow 2010 (NW2010 for short) is to associate workflows  with Content Types.This category of workflows is known as Reusable workflows.

As stated in Nintex Workflow 2010 User Manual

A resusable workflow template allows the workflow to be used on a content type, list or library through the
default SharePoint Workflow settings option.
Reusable workflow templates can be created for use within a single site or an entire site collection

In our case we are only interested in reusable workflows for content types.

Let’s disscuss the scenario when we need to automate the deployment of reusable workflow. It may take place for example, when there are several environments. The approach discussed here allows to deploy workflows during feature activation.

NW2010 API contains publishing infrastucture (Nintex.Workflow.Publishing namespace) that allow to programatically publish workflow templates.
Class Publish contains  method

WorkflowMetaData PublishAWorkflow(string wfName, NWActionConfigurations configs, Guid listId, SPWeb web, ImportContext importCtx, bool validate, SPContentTypeId contentTypeId, string changeNotes)

view raw
PublishAWorkflow.cs
hosted with ❤ by GitHub

that allows to associate workflow using ContentTypeId parameter.

The method below demonstrate how to deploy reusable workflow file by passing it file name, contenttype name and workflow name(NWFMappingEntry parameter)  using Nintex API PublishAWorkflow method.

/// <summary>
/// Publish Reusable Workflow
/// </summary>
/// <param name="mapping"></param>
public void PublishReusableWorkflow(NWFMappingEntry mapping)
{
SPContentType ct = web.ContentTypes[mapping.BindingName];
string workflowName = mapping.WorkflowName;
string pathToNWF = Path.Combine(properties.Definition.RootDirectory, mapping.WorkflowFileName);
byte[] workflowData = File.ReadAllBytes(pathToNWF);
string workflowFile = Utility.ConvertByteArrayToString(workflowData);
while ((int)workflowFile[0] != (int)char.ConvertFromUtf32(60)[0])
workflowFile = workflowFile.Remove(0, 1);
ExportedWorkflowWithListMetdata workflowWithListMetdata = ExportedWorkflowWithListMetdata.Deserialize(workflowFile);
string xmlMessage = workflowWithListMetdata.ExportedWorkflowSeralized;
SPListCollection lists = web.Lists;
Dictionary<string, Guid> dictionary = new Dictionary<string, Guid>(lists.Count);
foreach (SPList spList in lists)
{
if (!dictionary.ContainsKey(spList.Title.ToUpper()))
dictionary.Add(spList.Title.ToUpper(), spList.ID);
}
foreach (var listReference in workflowWithListMetdata.ListReferences)
{
string key = listReference.ListName.ToUpper();
if (dictionary.ContainsKey(key) && !dictionary.ContainsValue(listReference.ListId))
xmlMessage = xmlMessage.Replace(Utility.FormatGuid(listReference.ListId), Utility.FormatGuid(dictionary[key]));
}
var exportedWorkflow = WorkflowPart.Deserialize<ExportedWorkflow>(xmlMessage);
foreach (var config in exportedWorkflow.Configurations.ActionConfigs)
WorkflowRenderer.ProcessActionConfig(config);
Guid listId = Guid.Empty;
bool validateWorkflow = true;
Publish publish = new Publish(web);
publish.PublishAWorkflow(workflowName, exportedWorkflow.Configurations, listId, web, (ImportContext)null, validateWorkflow, ct.Id, string.Empty);
}

Project that demonstrates how to deploy Nintex reusable workflows may be found here

Initializing SharePoint People Editor using JavaScript in SharePoint 2010

Sometimes SharePoint PeopleEditor WebControl need to be initialized on the client side.

Initialize People Editor control

//Init People Picker
//peoplePickerId – SharePoint People Editor ClientID
//pickerEntityXml – PickerEntity in xml (see method ToXmlData for class PickerEntity)
function initPeoplePickerBox(peoplePickerId, pickerEntityXml) {
var $pe = $("#" + peoplePickerId);
var entityProps = {LoginName: pickerEntityXml.attr("Key"),
UserName: pickerEntityXml.attr("DisplayText"),
Description: pickerEntityXml.attr("Description")};
var entityExtendedProps = pickerEntityXml.find("ArrayOfDictionaryEntry");
var $peData = $pe.find("input[id$='hiddenSpanData']");
var $peDisplayArea = $pe.find("div[id$='_upLevelDiv']");
var displayData = "<span id='span{LoginName}' iscontenttype='true' tabindex='-1' class='ms-entity-resolved' contenteditable='false' title='{LoginName}'>" +
" <div style='display:none;' id='divEntityData' key='{LoginName}' displaytext='{UserName}' isresolved='True' description='{LoginName}'>" +
" <div data='{PickerEntityData}'></div>" +
" </div>" +
" <span id='content' tabindex='-1' contenteditable='false' onmousedown='onMouseDownRw(event);' oncontextmenu='onContextMenuSpnRw(event,ctx);'>{UserName}</span>" +
"</span>";
var pickerEntityData = convertFromXML(entityExtendedProps[0]);
displayData = displayData.replace(/{LoginName}/g, entityProps.LoginName);
displayData = displayData.replace(/{UserName}/g, entityProps.UserName);
displayData = displayData.replace('{PickerEntityData}', pickerEntityData);
$peDisplayArea.append(displayData);
$peData.val(displayData);
}

Clear People Editor control

//Clear People Picker
//peoplePickerId – SharePoint People Editor ClientID
function clearPeoplePickerBox(peoplePickerId) {
var $pe = $("#" + peoplePickerId);
var $peData = $pe.find("input[id$='hiddenSpanData']");
var $peDisplayArea = $pe.find("div[id$='_upLevelDiv']");
$peDisplayArea.children().remove();
$peData.val("");
}