Understanding the List Dialogs setting in SharePoint 2010

Overview

With the introduction of SharePoint 2010 two modes became available  when working with Libraries/List forms   from user experience perspective. Dialogs option in List Settings indicates whether to navigate the full page (Yes) or that the list form page is launched in a modal dialog (No)

XLV_DialogsOption

Figure 1. List settings 

Pay attention to the last part of the description that says:

Note: Dialogs may not be available on all forms.

Interesting, isn’t it, but what exactly does it mean? In order to find out we need to investigate how List Dialogs settings is handled in SharePoint 2010.  So, Let’s get started.

How it works

Depending on which option is selected link events for List/Library forms (New|Edit|View) are handled differently. When the “Launch forms in a dialog” is selected form pages are opened in modal dialog boxes.

How it is implemented

Through SharePoint Object Model the specified List settings for enabling/disabling modal dialog boxes is accessible via  SPList.NavigateForFormsPages property.   As it turns out, the value of  this property is passed to the XSL transform via  XsltListViewWebPart.ModifyXsltArgumentList method:

/// <summary>
/// Partial implementation of XsltListViewWebPart.ModifyXsltArgumentList method
/// The remaining code is omitted for clarity here
/// </summary>
protected override void ModifyXsltArgumentList(ArgumentClassWrapper argList)
{
argList.AddParameter("NavigateForFormsPages", string.Empty, this.SPList.NavigateForFormsPages ? (object) BaseXsltListWebPart.XslOneString : (object) BaseXsltListWebPart.XslZeroString);
}

The XSLT global parameter NavigateForFormsPages  declared in main.xsl file is utilized in CTXGeneration template:

<!–
Partial implementation of CTXGeneration template
(The remaining code is omitted for clarity here)
–>
<xsl:template name="CTXGeneration" ddwrt:ghost="always">
<script type="text/javascript">
ctx = new ContextInfo();
<!–Save List Dialogs parameter in NavigateForFormsPages property of ContextInfo structure–>
ctx.NavigateForFormsPages = <xsl:choose>
<xsl:when test="$NavigateForFormsPages='1'">true</xsl:when>
<xsl:otherwise>false</xsl:otherwise>
</xsl:choose>;
ctx<xsl:value-of select="$ViewCounter"/> = ctx;
g_ctxDict['ctx<xsl:value-of select="$ViewCounter"/>'] = ctx;
</script>
</xsl:template>

view raw
CTXGeneration.xsl
hosted with ❤ by GitHub

This template is intended for rendering  extra information about List settings on the client side  (ContextInfo structure). It is invoked every time when the List View is rendered on page. Pay attentions that List Dialogs setting that corresponds to NavigateForFormsPages property of ContextInfo structure.

And finally the event handler of the List form links is as follows:

//Handler for List form links in SharePoint 2010
// (from CORE.js)
function _EditLink2(elm, ctxNum)
{ULSrLq:;
var fn=function()
{ULSrLq:;
var url=GetGotoLinkUrl(elm);
if (url==null)
return;
var ctxT=window["ctx"+ctxNum];
if (ctxT !=null && ctxT.clvp !=null)
{
var clvp=ctxT.clvp;
if (FV4UI() && !ctxT.NavigateForFormsPages) //check if Dialogs option (NavigateForFormsPages property of ContextInfo) is set to 'No'
{
PreventDefaultNavigation();
clvp.ShowPopup(url); //open form in modal dialog boxes
return false;
}
}
GoToLink(elm); //navigate using href attribute of link
}
EnsureScript("inplview", typeof(inplview), fn);
}

view raw
_EditLink2.js
hosted with ❤ by GitHub

How the List Form link should be handled is determined by the NavigateForFormsPages parameter in the specified function, i.e. :

  • by navigating to a full page using href attribute of link
  • display form in modal dialog box

List Dialogs setting in ListViewWebPart

Now it is time to return to the question about why this settings is not available on all the forms. For answering on that question let me step back and explain a little bit about rendering a List View. Up until now we were talking only about rendering a List View via XsltListViewWebPart  that  handles view rendering for default lists, such as document libraries and announcements. But what about ListViewWebPart that is used for rendering specific List Views like  Calendar, Gantt or Chart Views.

The point is that this parameter (List Dialogs) does not take into account when a List View is rendered via ListViewWebPart. And the message “Dialogs that may not be available on all forms” concerns exactly this situation.

Then the question arise, how do we deal with the case where we need to open List Forms as a full pages for ListViewWebPart?  Let’s consider a real-world example when we need a Calendar forms to be opened as a full pages.

There are several ways how to achieve it, but we will consider only one, one of the simplest. The idea is to specify explicitly NavigateForFormsPages parameter for ContextInfo structure.

Steps:

1. Add CEWP into Calendar View page (Calendar.aspx)

2.  Place the following JavaScript code into CEWP

//Additional properties for ContextInfo () to be utilized in Calendar List View
//Specify actions navigate to the full page
var ContextInfo = (function() {
var ContextInfo_Orig = ContextInfo;
return function() {
ContextInfo_Orig();
this.NavigateForFormsPages = true; // Set navigate to the full page for list forms links
}
})();

That’s all, after that the Calendar forms will be opened as a full pages.

Integrating location and map functionality in SharePoint 2010

Overview

In SharePoint 2013 was  introduced a new field type named Geolocation that enables you to annotate SharePoint lists with location information. For example, you can now make lists “location-aware” and display latitude and longitude coordinates through Bing Maps. An entry is typically seen as a pushpin on a map view.

Due to the lack of these capabilities in SharePoint 2010 it was decided to fill the gap and bring location and map functionality into SharePoint 2010 and this is one the main reason why this project was initiated.

So, the aim of this project is to bring  location and map functionality into SharePoint 2010  (and more) the same way as they are currently available in SharePoint 2013.

Geolocation field

Geolocation field overview

SharePoint 2013 introduces a new field type named Geolocation that enables you to annotate SharePoint lists with location information.  The custom Geolocation field have been created as part of this project  that is intended for the same purposes in SharePoint 2010.

In columns of type Geolocation, you can enter location information as a pair of latitude and longitude coordinates in decimal degrees.

Add Geolocation column to a list

Geolocation column could be added to a list using standard capabilities of SharePoint 2010 UI as shown in Figure 1.

Figure 1. Add Geolocation column

CreategeoLocation

After the Geolocation column has been added, it could be used as shown below

Figure 2 New or Edit Form with Geolocation column
GeolocationNewForm

Figure 3. Display form with Geolocation column for Contacts list

GeolocationDispForm2

Figure 4. Representing Geolocation column in a list view

MapView_Popup2

Map view

Map View Overview

A map view is a SharePoint view that displays a map (with data obtained from the  Maps service ), using longitude and latitude entries from the Geolocation field type. When the Geolocation field type is available on the SharePoint list, a map view can be created  from the SharePoint UI. In the list, SharePoint 2010 displays the location on a map powered by Maps service, currently Bing Maps is supported only.

Create a map view

The following steps demonstrate how to create a map view from the SharePoint 2010 UI.

  1. Open the SharePoint 2010 list with Geolocation column.
  2. Choose Create view in Ribbon menu
  3. On the Choose a view type page, choose Map View, as shown in Figure 5.
    Figure 5. Choosing a view type
    MapViewFormat
  4. Save a view. A map view is created, as shown in Figure 6.
    Figure 6. Completed map view
    MapView

Resources

SharePoint 2010 Maps project is hosted on GitHub.

How to to retrieve and display Social Ratings in Content Query web part

Overview

In this post we will continue the discussion of accessing Social Data in Content Query web part that we started in the previous post. But this time we are going to customize Content Query web part in order to retrieve and display Social Ratings.  Our goal here to retrieve and display social ratings using the same way that they are being displayed  in List View.

When Ratings is enabled in List settings, the rating field is rendered in List View as shown below

ListViewWithRatings

and the customized Content Query web part for displaying Ratings control  will look like this

CBQWithSocialRatings

Prerequisites:

Implementation

So, lets start with the implementation of XSL stylesheet for rendering the Ratings control.

Social Ratings fields in SharePoint 2010

SharePoint 2010 comes with the following fields for Social Ratings:

  • AverageRating
  • RatingCount

For rendering AverageRating field in List View the  TEMPLATE\LAYOUTS\XSL\fldtypes_ratings.xsl is used. We will utilize templates from this file, but in order to make it work properly with CQWP, some modifications should be applied.

Ratings XSL stylesheet for CQWP

Templates definitions for the client side initialization and for rendering of of Ratings manager

<xsl:stylesheet xmlns:x="http://www.w3.org/2001/XMLSchema" xmlns:d="http://schemas.microsoft.com/sharepoint/dsp" version="1.0" exclude-result-prefixes="xsl msxsl ddwrt" xmlns:ddwrt="http://schemas.microsoft.com/WebParts/v2/DataView/runtime" xmlns:asp="http://schemas.microsoft.com/ASPNET/20" xmlns:__designer="http://schemas.microsoft.com/WebParts/v2/DataView/designer" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:msxsl="urn:schemas-microsoft-com:xslt" xmlns:SharePoint="Microsoft.SharePoint.WebControls" xmlns:ddwrt2="urn:frontpage:internal">
<xsl:param name="PopupAverageRatingLabel" />
<xsl:param name="PopupRatingCountLabel" />
<xsl:param name="PopupUserRatingLabel" />
<xsl:param name="PopupSubmitMessage" />
<xsl:param name="PopupDataNotAvailableMessage" />
<xsl:param name="PopupDataNotRatedMessage" />
<xsl:param name="ClickToRateMessage" />
<xsl:param name="CurrentAverageUnrated" />
<xsl:param name="CurrentAverageRating0_5Stars" />
<xsl:param name="CurrentAverageRating1_5Stars" />
<xsl:param name="CurrentAverageRating1_0Stars" />
<xsl:param name="CurrentAverageRating2_0Stars" />
<xsl:param name="CurrentAverageRating2_5Stars" />
<xsl:param name="CurrentAverageRating3_0Stars" />
<xsl:param name="CurrentAverageRating3_5Stars" />
<xsl:param name="CurrentAverageRating4_0Stars" />
<xsl:param name="CurrentAverageRating4_5Stars" />
<xsl:param name="CurrentAverageRating5_0Stars" />
<xsl:param name="SubmitNewRatingOpenerMessage" />
<xsl:param name="SubmitInstruction" />
<xsl:param name="Rate1StarMessage" />
<xsl:param name="Rate2StarMessage" />
<xsl:param name="Rate3StarMessage" />
<xsl:param name="Rate4StarMessage" />
<xsl:param name="Rate5StarMessage" />
<xsl:param name="IncreaseRatingInstruction" />
<xsl:param name="DecreaseRatingInstruction" />
<xsl:param name="EscapeInstruction" />
<xsl:param name="PopupWaitMessage" />
<xsl:template name="PrintAverageRating" >
<xsl:param name="thisNode" select="."/>
<xsl:variable name="url">
<xsl:call-template name="OuterTemplate.GetSafeLink">
<xsl:with-param name="UrlColumnName" select="'LinkUrl'"/>
</xsl:call-template>
</xsl:variable>
<xsl:variable name="title">
<xsl:choose>
<xsl:when test="string($thisNode/@Title)!=''">
<xsl:value-of select="$thisNode/@Title"/>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$thisNode/@FileLeafRef.Name"/>
</xsl:otherwise>
</xsl:choose>
</xsl:variable>
<xsl:variable name="ratingValueLocalized">
<xsl:choose>
<xsl:when test="$thisNode/@*[name()=current()/@Name]=''">0</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$thisNode/@*[name()=current()/@Name]"/>
</xsl:otherwise>
</xsl:choose>
</xsl:variable>
<xsl:variable name="ratingsData" select="ddwrt:GetRatingsData(string($thisNode/@ID))"/>
<xsl:variable name="controlId" select="$thisNode/@ID"/>
<xsl:variable name="ratingValue">
<xsl:value-of select="translate($ratingValueLocalized, ',','.')"/>
</xsl:variable>
<xsl:if test="not($ratingsData/ItemContentTypeContainsField) or $ratingsData/ItemContentTypeContainsField/node()='true'">
<xsl:variable name="ratingClass">
<xsl:choose>
<xsl:when test="number($ratingValue) &lt;= .25">ms-rating_0</xsl:when>
<xsl:when test="number($ratingValue) &lt;= .75">ms-rating_0_5</xsl:when>
<xsl:when test="number($ratingValue) &lt;= 1.25">ms-rating_1</xsl:when>
<xsl:when test="number($ratingValue) &lt;= 1.75">ms-rating_1_5</xsl:when>
<xsl:when test="number($ratingValue) &lt;= 2.25">ms-rating_2</xsl:when>
<xsl:when test="number($ratingValue) &lt;= 2.75">ms-rating_2_5</xsl:when>
<xsl:when test="number($ratingValue) &lt;= 3.25">ms-rating_3</xsl:when>
<xsl:when test="number($ratingValue) &lt;= 3.75">ms-rating_3_5</xsl:when>
<xsl:when test="number($ratingValue) &lt;= 4.25">ms-rating_4</xsl:when>
<xsl:when test="number($ratingValue) &lt;= 4.75">ms-rating_4_5</xsl:when>
<xsl:otherwise>ms-rating_5</xsl:otherwise>
</xsl:choose>
</xsl:variable>
<xsl:variable name="altMessage">
<xsl:choose>
<xsl:when test="$ratingClass='ms-rating_0'"><xsl:value-of select="string($CurrentAverageUnrated)"/></xsl:when>
<xsl:when test="$ratingClass='ms-rating_0_5'"><xsl:value-of select="string($CurrentAverageRating0_5Stars)"/></xsl:when>
<xsl:when test="$ratingClass='ms-rating_1'"><xsl:value-of select="string($CurrentAverageRating1_0Stars)"/></xsl:when>
<xsl:when test="$ratingClass='ms-rating_1_5'"><xsl:value-of select="string($CurrentAverageRating1_5Stars)"/></xsl:when>
<xsl:when test="$ratingClass='ms-rating_2'"><xsl:value-of select="string($CurrentAverageRating2_0Stars)"/></xsl:when>
<xsl:when test="$ratingClass='ms-rating_2_5'"><xsl:value-of select="string($CurrentAverageRating2_5Stars)"/></xsl:when>
<xsl:when test="$ratingClass='ms-rating_3'"><xsl:value-of select="string($CurrentAverageRating3_0Stars)"/></xsl:when>
<xsl:when test="$ratingClass='ms-rating_3_5'"><xsl:value-of select="string($CurrentAverageRating3_5Stars)"/></xsl:when>
<xsl:when test="$ratingClass='ms-rating_4'"><xsl:value-of select="string($CurrentAverageRating4_0Stars)"/></xsl:when>
<xsl:when test="$ratingClass='ms-rating_4_5'"><xsl:value-of select="string($CurrentAverageRating4_5Stars)"/></xsl:when>
<xsl:when test="$ratingClass='ms-rating_5'"><xsl:value-of select="string($CurrentAverageRating5_0Stars)"/></xsl:when>
</xsl:choose>
<xsl:if test="$ratingsData/FeatureActivated/node()='true' and $ratingsData/IsUserAnonymous/node()='false'">
<xsl:text> </xsl:text>
<xsl:value-of select="string($SubmitNewRatingOpenerMessage)"/>
</xsl:if>
</xsl:variable>
<span id="RatingsCtrl_{$controlId}">
<a class="ms-currentRating" href="javascript:;">
<img class="{$ratingClass}" src="{$ratingsData/RatingImageStripUrl/node()}" alt="{$altMessage}"/>
</a>
<xsl:if test="$ratingsData/FeatureActivated/node()='true' and $ratingsData/IsUserAnonymous/node()='false'">
<span class="ms-submitRating">
<img tabindex='0' alt='{string($Rate1StarMessage)} {string($SubmitInstruction)} {string($IncreaseRatingInstruction)} {string($EscapeInstruction)}' class='ms-rate1star'/>
<img tabindex='0' alt='{string($Rate2StarMessage)} {string($SubmitInstruction)} {string($IncreaseRatingInstruction)} {string($DecreaseRatingInstruction)} {string($EscapeInstruction)}' class='ms-rate2stars'/>
<img tabindex='0' alt='{string($Rate3StarMessage)} {string($SubmitInstruction)} {string($IncreaseRatingInstruction)} {string($DecreaseRatingInstruction)} {string($EscapeInstruction)}' class='ms-rate3stars'/>
<img tabindex='0' alt='{string($Rate4StarMessage)} {string($SubmitInstruction)} {string($IncreaseRatingInstruction)} {string($DecreaseRatingInstruction)} {string($EscapeInstruction)}' class='ms-rate4stars'/>
<img tabindex='0' alt='{string($Rate5StarMessage)} {string($SubmitInstruction)} {string($DecreaseRatingInstruction)} {string($EscapeInstruction)}' class='ms-rate5stars'/>
</span>
</xsl:if>
</span>
<xsl:if test="$ratingsData/FeatureActivated/node()='true' and $ratingsData/IsUserAnonymous/node()='false'">
<script type="text/javascript">
function RatingsControlLoader_<xsl:value-of select="$controlId"/>()
{
ratingsManager.CreateControl('<xsl:value-of select="ddwrt:EcmaScriptEncode($url)"/>', '<xsl:value-of select="ddwrt:EcmaScriptEncode($title)"/>', 'RatingsCtrl_<xsl:value-of select="$controlId"/>');
}
ExecuteOrDelayUntilEventNotified(RatingsControlLoader_<xsl:value-of select="$controlId"/>, 'RatingsManagerLoaded');
</script>
</xsl:if>
</xsl:if>
</xsl:template>
<xsl:template name="emit_RatingsInitialization">
<xsl:variable name="ratingsData" select="ddwrt:GetRatingsData(string(-1))"/>
<xsl:if test="$ratingsData/FeatureActivated/node()='true' and $ratingsData/IsUserAnonymous/node()='false'">
<script src="/_layouts/Ratings.js?rev={$ratingsData/CurrentBuildVersion/node()}" type="text/javascript" defer="defer"></script>
<script type="text/javascript">
var ratingsManager = null;
function RatingsManagerLoader()
{
var ratingsData = new RatingsCommonData(
'<![CDATA[<img src="/_layouts/images/loading16.gif"/> ]]><xsl:value-of select="string($PopupWaitMessage)"/>',
'<xsl:value-of select="string($PopupAverageRatingLabel)"/>',
'<xsl:value-of select="string($PopupRatingCountLabel)"/>',
'<xsl:value-of select="string($PopupUserRatingLabel)"/>',
'<xsl:value-of select="string($PopupSubmitMessage)"/>',
'<xsl:value-of select="string($PopupDataNotAvailableMessage)"/>',
'<xsl:value-of select="string($PopupDataNotRatedMessage)"/>',
'<xsl:value-of select="string($ClickToRateMessage)"/>',
'<xsl:value-of select="$ratingsData/SessionID/node()"/>',
'<xsl:value-of select="$ratingsData/WebID/node()"/>',
'<xsl:value-of select="ddwrt:EcmaScriptEncode($SiteUrl)"/>',
'<xsl:value-of select="$ratingsData/SiteID/node()"/>',
'<xsl:value-of select="$ratingsData/NewRatingIconUrl_EcmaScriptEncoded/node()"/>',
'<xsl:value-of select="$ratingsData/EmptyRatingIconUrl_EcmaScriptEncoded/node()"/>'
);
ratingsManager = new RatingsManager(ratingsData);
NotifyEventAndExecuteWaitingJobs('RatingsManagerLoaded');
}
ExecuteOrDelayUntilScriptLoaded(RatingsManagerLoader, 'ratings.js');
</script>
</xsl:if>
</xsl:template>
</xsl:stylesheet>

view raw
RatingsStyle.xsl
hosted with ❤ by GitHub

Main XSL stylesheet

Custom ContentQueryMain.xsl is used, in which  the template for client side initialization of Ratings control is invoked

Source

Item XSL stylesheet

Custom ItemStyle.xsl is used, in which  the template for rendering Ratings control per page is invoked

Source

Ratings XSL Parameters

Parameter values are retrieved from resource file  and are passed via ParamaterBindings web part property

<ParameterBindings>
<ParameterBinding Name="PopupAverageRatingLabel" Location="Resource(sps,Ratings_PopupAverageRatingLabel)" />
<ParameterBinding Name="PopupRatingCountLabel" Location="Resource(sps,Ratings_PopupRatingCountLabel)"/>
<ParameterBinding Name="PopupUserRatingLabel" Location="Resource(sps,Ratings_PopupUserRatingLabel)"/>
<ParameterBinding Name="PopupSubmitMessage" Location="Resource(sps,Ratings_PopupSubmitMessage)"/>
<ParameterBinding Name="PopupDataNotAvailableMessage" Location="Resource(sps,Ratings_PopupDataNotAvailableMessage)"/>
<ParameterBinding Name="PopupDataNotRatedMessage" Location="Resource(sps,Ratings_PopupDataNotRatedMessage)"/>
<ParameterBinding Name="ClickToRateMessage" Location="Resource(sps,Ratings_ClickToRateMessage)"/>
<ParameterBinding Name="CurrentAverageUnrated" Location="Resource(sps,Ratings_CurrentAverageUnrated)"/>
<ParameterBinding Name="CurrentAverageRating0_5Stars" Location="Resource(sps,Ratings_CurrentAverageRating0_5Stars)"/>
<ParameterBinding Name="CurrentAverageRating1_5Stars" Location="Resource(sps,Ratings_CurrentAverageRating1_5Stars)"/>
</ParameterBindings>

Let’s summarize.

In order to configure CQWP  for displaying Social Ratings , the following steps should be accomplished:

References

How to retrieve and display social comments in Content Query web part

Introduction

Using social comments in Publishing pages is pretty common scenario for SharePoint Publishing Sites. In comparison to page fields (Page Content, Title, Page Image and etc.)  that are inserted into the “slots” of the page layout and associated with the content type of the publishing page, social comments are stored separately.  Social comments are stored in separate DB and the comment entry is associated by the page Url on which comment has been given.

Let’s take a look at several approaches how to display social comments for Publishing pages in Content Query web part as shown on picture below.

Prerequisites: to enable social comments in Publishing pages the custom page layout with Note Board web part is used  for demonstration here.

CBQ_Comments

Extending Content By Query web part

In this approach the social comments are retrieved and saved in results before it is sent to the XSL transform using  ProcessDataDelegate delegate of Content Query web part. For retrieving social comments, SocialCommentManager class is utilized, which represents the entry point in  SharePoint object model (OM) that exposes methods to do work with social comments or notes.

So, in order to attach method for processing of social comments to a delegate   ProcessDataDelegate we need to subclass Content Query web part as demonstrated below:

/// <summary>
/// Adding social comments to the results of Content Query web part
/// </summary>
[ToolboxItem(false)]
public class SocialCBQ : ContentByQueryWebPart
{
protected override void OnInit(EventArgs e)
{
base.OnInit(e);
this.ProcessDataDelegate = ProcessSocialData;
}
private DataTable ProcessSocialData(DataTable data)
{
var context = SPServiceContext.GetContext(SPContext.Current.Site);
scm = new SocialCommentManager(context);
data.Columns.Add("PageUrl", typeof(string));
data.Columns.Add("PageComments", typeof(int));
foreach (DataRow row in data.Rows)
{
var fileRefVal = new SPFieldLookupValue((string)row[SPBuiltInFieldId.FileRef.ToString("B")]);
string pageUrl = SPContext.Current.Site.MakeFullUrl("/" + fileRefVal.LookupValue);
var pageComments = scm.GetCount(new Uri(pageUrl));
row["PageUrl"] = pageUrl;
row["PageComments"] = pageComments;
}
return data;
}
private SocialCommentManager scm;
}

view raw
SocialCBQ.cs
hosted with ❤ by GitHub

And the final step is to customize template for rendering item (ItemStyle.xsl) in order to render social columns  (comment count per page in our case) in Content Query web part:

<div class="comments">
Comments: <span class="comments" pageurl="{@PageUrl}"><xsl:value-of select="@PageComments" /></span>
</div>

Utilizing SharePoint Web Services  for retrieving social comment in CQWP

In this approach we are not going to subclass Content Query web part, but implement social comments retrieving and binding on the client side.

SharePoint Web Services exposes Social Data Service that provides methods for remote clients to Create, Read, Update, and Delete (CRUD) social data.

The following JavaScript code demonstrates how to utilize SharePoint Web Services for retrieving comment count per page and to bind it to  comments item template (ItemStyle.xsl)

function CountCommentsOnUrl(url,result)
{
var soapEnv =
"<soap:Envelope xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance&#39; xmlns:xsd='http://www.w3.org/2001/XMLSchema&#39; xmlns:soap='http://schemas.xmlsoap.org/soap/envelope/'&gt; \
<soap:Body> \
<CountCommentsOnUrl xmlns='http://microsoft.com/webservices/SharePointPortalServer/SocialDataService'&gt; \
<url>" + url + "</url> \
</CountCommentsOnUrl> \
</soap:Body> \
</soap:Envelope>";
$.ajax({
pageurl: url,
result: result,
url: "/_vti_bin/SocialDataService.asmx?op=CountCommentsOnUrl",
type: "POST",
dataType: "xml",
data: soapEnv,
contentType: "text/xml; charset=\"utf-8\"",
success: function(data, status, xhr){
if(this.result !== undefined) {
var commentCount = $('CountCommentsOnUrlResponse', data).find('CountCommentsOnUrlResult').text();
this.result(commentCount);
}
}
});
}
$(function() {
$('span.comments').each(function() {
var pageUrl = $(this).attr('pageurl');
var comment = $(this);
CountCommentsOnUrl(pageUrl,function(commentCount){
comment.text(commentCount);
});
});
});

Code excerpt for comment item from ItemStyle.xsl:

<div class="comments">
Comments: <span class="comments" pageurl="{@LinkUrl}"></span>
</div>

References

Beyond the Slideshow web part capabilities in SharePoint 2010

Overview

In one of the previous post we have started the discussion of customizing   Slideshow web part, in particular it was demonstrated  how to provide additional filtering for picture items. This time we’re going to go further and consider different scenarios of using SharePoint SlideShow capabilities. We deliberately do not consider the use of  third party libraries for Slideshow or creating custom web parts, but try to build new experience using existing tools only.

1. Customize the display for Slideshow control: display additional picture properties

Suppose in addition to standard properties, custom properties should be displayed  from Picture Library in Slideshow web part.

PictureLibCustomFields

The following  fields are retrieved  from Picture Library for Slideshow:

So, our goal is to display slideshow using custom layout as shown below

CarsSlideshow

Solution:

Solution consist of the following parts:

  • load custom picture properties, see loadCarPicturesAdditionalInfo method for details
  • Slideshow library (imglib.js) methods overriding for slideshow object initialization, picture  changing and displaying
function SlideshowObjectInitializer() {
ChangePic = (function(ChangePicOrig) {
return function() {
var ssObj = arguments[0]; //SlideShow object
if(typeof ssObj.additionalInfo != "undefined")
ChangePicOrig.apply(this, arguments);
};
})(ChangePic);
ShowPic = (function(ShowPicOrig) {
return function() {
ShowPicOrig.apply(this, arguments); //call original ShowPic
var ssObj = arguments[0]; //SlideShow object
ShowAdditionalPicInfo(ssObj);
};
})(ShowPic);
function ShowAdditionalPicInfo(ssObj)
{
var curPicIdx=ssObj.index; //current picture index
if(ssObj.additionalInfo.length == 0)
return;
var picEntry = ssObj.additionalInfo[curPicIdx];
var ssobj_ext_cell = '<td>';
ssobj_ext_cell += '<div style="font-size:22px;"><span style="font-weight:bold">Car Model:</span>' + picEntry.CarModel + '</div>';
ssobj_ext_cell += '<div style="font-size:22px;"><span style="font-weight:bold">Car Description:</span>' + picEntry.CarDesc + '</div>';
ssobj_ext_cell += '</td>';
var ssobj_row = jQuery(ssObj.cell).closest('tr');
if(ssobj_row.find('td').length > 1) {
ssobj_row.find('td:nth-child(2)').replaceWith(ssobj_ext_cell);
}
else
ssobj_row.append(ssobj_ext_cell);
}
SlideshowObject = (function(SlideshowObjectOrig) {
return function() {
SlideshowObjectOrig.apply(this, arguments);
var ssobj = this;
ExecuteOrDelayUntilScriptLoaded(function(){
loadCarPicturesAdditionalInfo(function(picEntries){
ssobj.additionalInfo = picEntries;
ChangePic(ssobj);
});
},'SP.js');
};
})(SlideshowObject);
}
function loadCarPicturesAdditionalInfo(cbPicsResults) {
var context = new SP.ClientContext.get_current();
var web = context.get_web();
var list = web.get_lists().getByTitle("Pictures");
var viewXml = '<View></View>';
var query = new SP.CamlQuery();
query.set_viewXml(viewXml);
var items = list.getItems(query);
context.load(items,"Include(CarModel,CarDesc)");
context.add_requestSucceeded(onLoaded);
context.add_requestFailed(onFailure);
context.executeQueryAsync();
function onLoaded() {
var picEntries = [];
var itemsCount = items.get_count();
for (i = 0; i < itemsCount; i++) {
var item = items.itemAt(i);
var picEntry = item.get_fieldValues();
picEntries.push(picEntry);
}
cbPicsResults(picEntries);
}
function onFailure() {
cbPicsResults(null);
}
}

view raw
SSObj_customprops.js
hosted with ❤ by GitHub

Usage

Save JavaScript code to the file and embed it into the page with Slideshow web part  as demonstrated below

<script src="/_layouts/SE/imglibutils.js" type="text/javascript"></script>
<script type="text/javascript">
ExecuteOrDelayUntilScriptLoaded(SlideshowObjectInitializer, 'imglib.js');
</script>

2. Customize the display for Slideshow control: display original pictures

In Slideshow web part, picture is initialized with field value that contains the Url of  Web image (EncodedAbsWebImgUrl  field). Unfortunately it is not supported to configure in web part what image type (original, web or thumbnail) should be displayed in Slideshow The solution that demonstrated below allows to display original images instead of web images in Slideshow web part.

Solution:

In order to specify original images, method overriding for picture initialization is used:

function SlideshowObjectInitializer() {
ShowPic = (function(ShowPicOrig) {
return function() {
var ssObj = arguments[0]; //SlideShow object
var curPicIdx=ssObj.index; //current picture index
ShowPicOrig.apply(this, arguments); //call original ShowPic
//apply some changes to display original picture in SlideShow control
ssObj.image.src = ssObj.linkArray[curPicIdx]; //display original image instead of web image
//change picture & container size to auto instead of fixed (by default web image size is used)
ssObj.image.setAttribute('height','100%');
ssObj.image.setAttribute('width','100%');
var cell = ssObj.cell;
cell.style.width = 'auto';
cell.style.height = 'auto';
cell.style.display = '';
var pcell = ssObj.cell.parentNode;
pcell.style.width = 'auto';
pcell.style.height = 'auto';
};
})(ShowPic);
}
ExecuteOrDelayUntilScriptLoaded(SlideshowObjectInitializer, 'imglib.js');

Usage

One of the most simple way to apply these changes is to embed specified JavaScript code via Content Editor web part (CEWP), for more details please follow this article.

  • Save JavaScript code to the file, for example in SlideshowObjectInitializer.txt and upload it to SiteAssets Library
  • Add CEWP on page where Slideshow web part is located and in the Content Editor tool pane, under Content Link property, type /SiteAssets/SlideshowObjectInitializer.txt

3. Slideshow List View

Slideshow List View is only available for Pictures Library. It is pretty common scenario when another types of repositories are used for storing images, for example Assets Library. Let’s look at how to create a Slideshow  List View for images stored in Assets Library.

Solution:

Slideshow List View

<xsl:stylesheet xmlns:x="http://www.w3.org/2001/XMLSchema"
xmlns:d="http://schemas.microsoft.com/sharepoint/dsp"
version="1.0" exclude-result-prefixes="xsl msxsl ddwrt x d asp __designer SharePoint ddwrt2"
xmlns:ddwrt="http://schemas.microsoft.com/WebParts/v2/DataView/runtime"
xmlns:asp="http://schemas.microsoft.com/ASPNET/20"
xmlns:__designer="http://schemas.microsoft.com/WebParts/v2/DataView/designer"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:msxsl="urn:schemas-microsoft-com:xslt"
xmlns:SharePoint="Microsoft.SharePoint.WebControls"
xmlns:ddwrt2="urn:frontpage:internal">
<xsl:import href="/_layouts/xsl/main.xsl"/>
<xsl:output method="html" indent="no"/>
<xsl:template match="View" mode="full" ddwrt:ghost="always">
<tr class="ms-viewheadertr"></tr>
<tr>
<td>
<!– Slideshow control –>
<table border="0" style="table-layout: fixed">
<tbody>
<tr>
<td >
<div id="slidecontrol_cell" style="display: table-cell; vertical-align: middle; text-align: center;">
<span style="vertical-align: middle; height: 100%; display: inline-block"></span>
<a id="slidecontrol_link" target="_blank">
<img id="slidecontrol_curr" style="opacity: 0.9900000000000007; border: 0px; vertical-align: middle;" alt=""/>
</a>
</div>
</td>
</tr>
<tr>
<td style="height: 75px">
<div style="height: 75px; opacity: 0.9900000000000007;" id="slidecontrol_text">
<span id="slidecontrol_title" class="ms-slideshow-title"></span>
<br/>
</div>
</td>
</tr>
<tr>
<td style="text-align: center">
<a id="btn_prev" >
<img border="0" style="position: relative; cursor: hand" onmouseover="HiliteButton()" onmouseout="DemoteButton()" src="/_layouts/images/plprev1.gif" alt="Previous Image"/>
</a>
<a id="btn_pp" >
<img border="0" style="position: relative; cursor: hand" onmouseover="HiliteButton()" onmouseout="DemoteButton()" src="/_layouts/images/plpause1.gif" id="slidecontrol_playpause" alt="Pause"/>
</a>
<a id="btn_next">
<img border="0" style="position: relative; cursor: hand" onmouseover="HiliteButton()" onmouseout="DemoteButton()" src="/_layouts/images/plnext1.gif" alt="Next Image"/>
</a>
</td>
</tr>
</tbody>
</table>
<img id="slidecontrol_next" width="0" height="0" style="visibility: hidden" />
<img id="slidecontrol_prev" width="0" height="0" style="visibility: hidden" />
<img id="slidecontrol_pp" width="0" height="0" style="visibility: hidden" />
</td>
</tr>
<script type="text/javascript">
var slidecontrol_slideshowObject;
ExecuteOrDelayUntilScriptLoaded(function(){
slidecontrol_slideshowObject = createSlideControl('slidecontrol_');
},'SP.js');
</script>
<xsl:apply-templates mode="footer" select="." />
</xsl:template>
<xsl:template name="SlideshowViewOverride" mode="RootTemplate" match="View" ddwrt:dvt_mode="root">
<script type='text/javascript' src="/_layouts/1033/imglib.js"></script>
<script type='text/javascript' src="/_layouts/yaspp/slideshow.js"></script>
<!–script src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js"></script–>
<script type="text/javascript">
</script>
<xsl:call-template name="View_Default_RootTemplate"/>
</xsl:template>
</xsl:stylesheet>

Slideshow control initialization and retrieving picture entries from Assets Library

//initialize SlideshowObject control
function createSlideControl(slidecontrolId)
{
loadPicturesInfo(function(picEntries) {
var slidecontrol_slideshowObject = new SlideshowObject(slidecontrolId, picEntries.src, picEntries.fullImageSrc, picEntries.title, picEntries.description, picEntries.height, picEntries.width, 15, 1.0);
ChangePic(slidecontrol_slideshowObject);
InitSlideControlNavButtons(slidecontrol_slideshowObject);
});
}
//
function InitSlideControlNavButtons(slideshowObject) {
var btn_prev = document.getElementById("btn_prev");
AddEvtHandler(btn_prev, "onclick", function() { NextPrevious(slideshowObject, false);});
var btn_pp = document.getElementById("btn_pp");
AddEvtHandler(btn_pp, "onclick", function() { PlayPause(slideshowObject);});
var btn_next = document.getElementById("btn_next");
AddEvtHandler(btn_next, "onclick", function() { NextPrevious(slideshowObject, true);});
}
//retrieve picture entries for SlideObject control
function loadPicturesInfo(cbPicsResults) {
var context = new SP.ClientContext.get_current();
var web = context.get_web();
var list = web.get_lists().getByTitle(ctx.ListTitle);
var viewXml = '<View></View>';
var query = new SP.CamlQuery();
query.set_viewXml(viewXml);
var items = list.getItems(query);
context.load(items,"Include(Title,EncodedAbsWebImgUrl,EncodedAbsUrl,ImageWidth,ImageHeight)");
context.add_requestSucceeded(onLoaded);
context.add_requestFailed(onFailure);
context.executeQueryAsync();
function onLoaded() {
var widthArray = [];
var heightArray = [];
var pictureArray = [];
var linkArray = [];
var titleArray = [];
var descriptionArray = [];
var itemsCount = items.get_count();
for (i = 0; i < itemsCount; i++) {
var item = items.itemAt(i);
var picEntry = item.get_fieldValues();
titleArray.push(picEntry.Title);
pictureArray.push(picEntry.EncodedAbsWebImgUrl);
linkArray.push(picEntry.EncodedAbsUrl);
descriptionArray.push('');
widthArray.push(picEntry.ImageWidth);
heightArray.push(picEntry.ImageHeight);
}
picEntries = {title:titleArray,description:descriptionArray,fullImageSrc: linkArray,src:pictureArray, width:widthArray,height:heightArray};
cbPicsResults(picEntries);
}
function onFailure() {
cbPicsResults(null);
}
}

view raw
slideshow.js
hosted with ❤ by GitHub

4. Aggregate picture items and render as Slideshow

The last example demonstrates how to display slideshow for pictures aggregated  from site collection.  For aggregating pictures from site collection, Content Query web part is utilized.

Solution

OuterTemplate.SlideShowBody template is intended for rendering Slideshow control in CQWP

<xsl:template name="OuterTemplate.SlideShowBody">
<xsl:param name="Rows" />
<xsl:param name="FirstRow" />
<xsl:param name="LastRow" />
<script type="text/javascript">
function loadScript(url, callback)
{
// adding the script tag to the head as suggested before
var head = document.getElementsByTagName('head')[0];
var script = document.createElement('script');
script.type = 'text/javascript';
script.src = url;
// then bind the event to the callback function
// there are several events for cross browser compatibility
script.onreadystatechange = callback;
script.onload = callback;
// fire the loading
head.appendChild(script);
}
function InitSlideControlNavButtons(slideshowObject) {
var btn_prev = document.getElementById("btn_prev");
AddEvtHandler(btn_prev, "onclick", function() { NextPrevious(slideshowObject, false);});
var btn_pp = document.getElementById("btn_pp");
AddEvtHandler(btn_pp, "onclick", function() { PlayPause(slideshowObject);});
var btn_next = document.getElementById("btn_next");
AddEvtHandler(btn_next, "onclick", function() { NextPrevious(slideshowObject, true);});
}
<xsl:text>var widthArray = [</xsl:text>
<xsl:for-each select="$Rows">
<xsl:value-of select="@ImageWidth" />
<xsl:if test="position() != last()">, </xsl:if>
</xsl:for-each>
<xsl:text>];</xsl:text>
<xsl:text>var linkArray = [</xsl:text>
<xsl:for-each select="$Rows">
<xsl:value-of select="concat('&quot;',@LinkUrl,'&quot;')" />
<xsl:if test="position() != last()">, </xsl:if>
</xsl:for-each>
<xsl:text>];</xsl:text>
<xsl:text>var heightArray = [</xsl:text>
<xsl:for-each select="$Rows">
<xsl:value-of select="@ImageHeight" />
<xsl:if test="position() != last()">, </xsl:if>
</xsl:for-each>
<xsl:text>];</xsl:text>
<xsl:text>var pictureArray = [</xsl:text>
<xsl:for-each select="$Rows">
<xsl:value-of select="concat('&quot;',@LinkUrl,'&quot;')" />
<xsl:if test="position() != last()">, </xsl:if>
</xsl:for-each>
<xsl:text>];</xsl:text>
<xsl:text>var titleArray = [</xsl:text>
<xsl:for-each select="$Rows">
<xsl:value-of select="concat('&quot;',@Title,'&quot;')" />
<xsl:if test="position() != last()">, </xsl:if>
</xsl:for-each>
<xsl:text>];</xsl:text>
<xsl:text>var descriptionArray = [</xsl:text>
<xsl:for-each select="$Rows">
<xsl:value-of select="concat('&quot;',@Description,'&quot;')" />
<xsl:if test="position() != last()">, </xsl:if>
</xsl:for-each>
<xsl:text>];</xsl:text>
loadScript("/_layouts/1033/imglib.js", function()
{
var slidecontrol = new SlideshowObject('slidecontrol_', pictureArray, linkArray, titleArray, descriptionArray, heightArray, widthArray, 15, 1.0);
ChangePic(slidecontrol);
InitSlideControlNavButtons(slidecontrol);
});
</script>
<xsl:call-template name="SlideShowControl" >
</xsl:call-template>
</xsl:template>
<xsl:template name="SlideShowControl">
<table border="0" style="table-layout: fixed">
<tbody>
<tr>
<td >
<div id="slidecontrol_cell" style="display: table-cell; vertical-align: middle; text-align: center;">
<span style="vertical-align: middle; height: 100%; display: inline-block"></span>
<a id="slidecontrol_link" target="_blank">
<img id="slidecontrol_curr" style="opacity: 0.9900000000000007; border: 0px; vertical-align: middle;" alt=""/>
</a>
</div>
</td>
</tr>
<tr>
<td style="height: 75px">
<div style="height: 75px; opacity: 0.9900000000000007;" id="slidecontrol_text">
<span id="slidecontrol_title" class="ms-slideshow-title"></span>
<br/>
</div>
</td>
</tr>
<tr>
<td style="text-align: center">
<a id="btn_prev" >
<img border="0" style="position: relative; cursor: hand" onmouseover="HiliteButton()" onmouseout="DemoteButton()" src="/_layouts/images/plprev1.gif" alt="Previous Image"/>
</a>
<a id="btn_pp" >
<img border="0" style="position: relative; cursor: hand" onmouseover="HiliteButton()" onmouseout="DemoteButton()" src="/_layouts/images/plpause1.gif" id="slidecontrol_playpause" alt="Pause"/>
</a>
<a id="btn_next">
<img border="0" style="position: relative; cursor: hand" onmouseover="HiliteButton()" onmouseout="DemoteButton()" src="/_layouts/images/plnext1.gif" alt="Next Image"/>
</a>
</td>
</tr>
</tbody>
</table>
<img id="slidecontrol_next" width="0" height="0" style="visibility: hidden" />
<img id="slidecontrol_prev" width="0" height="0" style="visibility: hidden" />
<img id="slidecontrol_pp" width="0" height="0" style="visibility: hidden" />
</xsl:template>

Usage

  • Configure source properties (List Type: Picture Library, Content Type:  Picture)PicturesCQWP
  • Specify additional fields for retrieving via  CommonViewFields property. For more details how to display custom fields in a CQWP, follow this article
<property name="CommonViewFields" type="string">Description,Text;ImageWidth,Integer;ImageHeight,Integer;Title,Text;</property>

view raw
CQWP_Pictures.xml
hosted with ❤ by GitHub

  • Replace OuterTemplate.Body template with OuterTemplate.SlideShowBody in ContentQueryMain.xsl. For more details how to customize XSL for the Content Query Web Part follow this article

Conclusion

The main idea of this post  was to demonstrate how to combine different components available in SharePoint 2010 in order to build new functionality without creating new one from scratch (i.e.: new web parts) or using third party components.

Customizing Search Results (SharePoint 2010): People Search Results Custom Sorting using XSLT

Overview

By default People Search Results web part sorting capabilities are limited by the following options:

  • Relevance (default)
  • Social Distance
  • Name

Below is presented XSLT based approach how to provide additional sorting options for People Search Results web part.

But before we proceed let me clarify the main limitation of this solution:

  • the specified method allows to sort  search results returned for page only (to control results returned for page ResultsPerPage property is used)
  • applying sorting take place during XSLT transformation (in our case it  is applied to relevant results)

Solution description

Provide custom sorting options values

ParameterBindings property is used for storing custom sort options values and passing them to XSLT:

<ParameterBindings>
<ParameterBinding Name="CustomNameSortLabels" DefaultValue="Job Title,Department,Last Name" />
<ParameterBinding Name="CustomNameSortValues" DefaultValue="jobtitle,department,lastname" />
<ParameterBinding Name="V1FromUrl" Location="QueryString(v1)" />
<ParameterBinding Name="QueryFromUrl" Location="QueryString(k)" />
<ParameterBinding Name="HsFromUrl" Location="QueryString(hs1)" />
<ParameterBinding Name="RmFromUrl" Location="QueryString(rm1)" />
</ParameterBindings>

,where

CustomNameSortLabels and CustomNameSortValues   are used for storing  custom sort option labels and values respectively.

Customize Sort Options  in People Search Results

In order to display custom sort options the following XSLT template is used:

<xsl:template name="GetCustomSortResultUrl">
<xsl:param name="NameSortValue"/>
<xsl:value-of select="concat(concat(concat('peopleresults.aspx?k=',$QueryFromUrl),'&amp;v1='),$NameSortValue)"/>
</xsl:template>
<xsl:template name="CustomSortOptions">
<xsl:param name="NameSortValues" select="$CustomNameSortValues"/>
<xsl:param name="NameSortLabels" select="$CustomNameSortLabels"/>
<xsl:param name="separator" select="','"/>
<xsl:choose>
<xsl:when test="not(contains($NameSortValues, $separator))">
<xsl:if test="string-length($NameSortValues) &gt; 0">
<xsl:variable name="NameSortUrl">
<xsl:call-template name="GetCustomSortResultUrl">
<xsl:with-param name="NameSortValue" select="$NameSortValues"/>
</xsl:call-template>
</xsl:variable>
<xsl:element name="option">
<xsl:attribute name="value">
<xsl:value-of select="ddwrt:EnsureAllowedProtocol(string($NameSortUrl))"/>
</xsl:attribute>
<xsl:if test="$NameSortValues = $V1FromUrl and string-length($HsFromUrl) = 0">
<xsl:attribute name="selected">selected</xsl:attribute>
</xsl:if>
<xsl:value-of select="$NameSortLabels"/>
</xsl:element>
</xsl:if>
</xsl:when>
<xsl:otherwise>
<xsl:variable name="NameSortUrl">
<xsl:call-template name="GetCustomSortResultUrl">
<xsl:with-param name="NameSortValue" select="substring-before($NameSortValues, $separator)"/>
</xsl:call-template>
</xsl:variable>
<xsl:element name="option">
<xsl:attribute name="value">
<xsl:value-of select="ddwrt:EnsureAllowedProtocol(string($NameSortUrl))"/>
</xsl:attribute>
<xsl:if test="substring-before($NameSortValues, $separator) = $V1FromUrl">
<xsl:attribute name="selected">selected</xsl:attribute>
</xsl:if>
<xsl:value-of select="substring-before($NameSortLabels, $separator)"/>
</xsl:element>
<xsl:call-template name="CustomSortOptions">
<xsl:with-param name="NameSortValues" select="substring-after($NameSortValues, $separator)"/>
<xsl:with-param name="NameSortLabels" select="substring-after($NameSortLabels, $separator)"/>
<xsl:with-param name="separator" select="','"/>
</xsl:call-template>
</xsl:otherwise>
</xsl:choose>
</xsl:template>

Complete XSLT file for People Search Results  could be found here

Below is shown sorting options control after applying specified XSLT and providing Parameter Binding property value from above example

SortOptions

Sorting for search results is defined using XSLT sorting element:

<xsl:for-each select="All_Results/Result">
<xsl:sort data-type="text" order="ascending" select="*[name() = $V1FromUrl]"/>
<xsl:call-template name="SingleResult"/>
</xsl:for-each>

Complete XSLT file for People Search Results with custom Sort Options could be found here

Results

People Search Result page with results sorted by Last Name is shown below

PeopleSearchResultsCustomSort

References

Bringing Map functionality into SharePoint 2010: Rendering Map List View

Overview

SharePoint 2013 introduces functionality to integrate location information and maps in SharePoint lists and location-based web and mobile apps for SharePoint with the following capabilities:

  • new field type named Geolocation that enables you to annotate SharePoint lists with location information. The built-in Geolocation field can render only with Bing Maps. However, you can create a custom field by using the Geolocation field as a parent field type, for example see my blog post about using Google Maps as map service.
  • Map View that displays a map (with data obtained from the Bing Maps service), using longitude and latitude entries from the Geolocation field type

Client-side rendering for Map List View in SharePoint 2013

Regarding Map View, SharePoint 2013 utilizes client side rendering framework for List View that allows to define the rendering logic of SharePoint list views using HTML/JavaScript. There is already predefined rendering template in SharePoint 2013  for Binq Maps service that is used when Map View is created, for more details see Create a map view for the Geolocation field in SharePoint 2013.

Map List View in SharePoint 2010

But what about SharePoint 2010? Let’s discuss one approach related with customizing List View for  XSLTListViewWebPart (XLV) . So, in proposed solution  geographical locations are stored in Custom List and custom View is used to render data on Map using Google Maps service For example, list items GeoMapDefaultView

will be represented in Map View as shown below

GeoMapView

Implementation of Map List View in SharePoint 2010

As was noted earlier for storing geographical location on a map and visualizing it in Map View we will define Custom List named GeoMap List.

GeoMap Content Type

For storing geographical locations we define the following Content Type

<?xml version="1.0" encoding="utf-8"?>
<Elements xmlns="http://schemas.microsoft.com/sharepoint/">
<!– Parent ContentType: Item (0x01) –>
<ContentType ID="0x010087e1abb3659f42f6ad024894ec514f93"
Name="GeoMap"
Group="GeoMap"
Description="GeoMap Content Type"
Inherits="TRUE"
Version="0">
<FieldRefs>
<FieldRef ID="{F3252F03-F69E-40fb-91F7-8BD364D0882B}" Name="MapAddress1"/>
<FieldRef ID="{FBCDD54F-21AA-4eab-A376-4BC531FF264F}" Name="MapAddress2"/>
<FieldRef ID="{638D5C28-6DFC-4642-AC7C-5377E478F5CC}" Name="MapCity"/>
<FieldRef ID="{1966B506-0642-4b00-8B56-5B872C725B6A}" Name="MapState"/>
<FieldRef ID="{594036C6-29C6-4c71-A271-6721C171E675}" Name="MapZip"/>
<FieldRef ID="{6A85673B-2EE1-483d-AD5D-57161DFE8237}" Name="MapCountry"/>
<FieldRef ID="{EBFA40F7-A21A-4f4c-B941-036F5A360E0C}" Name="MapLatitude"/>
<FieldRef ID="{ADDBDAC0-123C-46d5-9BA0-0D7EA29E5711}" Name="MapLongitude"/>
<FieldRef ID="{CDF90965-628A-4cf0-91E3-D6F3DBE233CC}" Name="MapAdditionalInfo"/>
</FieldRefs>
</ContentType>
<Field Type="Text" DisplayName="Address1" Required="FALSE" ID="{F3252F03-F69E-40fb-91F7-8BD364D0882B}" SourceID="http://schemas.microsoft.com/sharepoint/v3" StaticName="MapAddress1" Name="MapAddress1" Group="GeoMap" />
<Field Type="Text" DisplayName="Address2" Required="FALSE" ID="{FBCDD54F-21AA-4eab-A376-4BC531FF264F}" SourceID="http://schemas.microsoft.com/sharepoint/v3" StaticName="MapAddress2" Name="MapAddress2" Group="GeoMap" />
<Field Type="Text" DisplayName="City" Required="FALSE" ID="{638D5C28-6DFC-4642-AC7C-5377E478F5CC}" SourceID="http://schemas.microsoft.com/sharepoint/v3" StaticName="MapCity" Name="MapCity" Group="GeoMap" />
<Field Type="Text" DisplayName="State" Required="FALSE" ID="{1966B506-0642-4b00-8B56-5B872C725B6A}" SourceID="http://schemas.microsoft.com/sharepoint/v3" StaticName="MapState" Name="MapState" Group="GeoMap" />
<Field Type="Text" DisplayName="Zip" Required="FALSE" ID="{594036C6-29C6-4c71-A271-6721C171E675}" SourceID="http://schemas.microsoft.com/sharepoint/v3" StaticName="MapZip" Name="MapZip" Group="GeoMap" />
<Field Type="Text" DisplayName="Country" Required="FALSE" ID="{6A85673B-2EE1-483d-AD5D-57161DFE8237}" SourceID="http://schemas.microsoft.com/sharepoint/v3" StaticName="MapCountry" Name="MapCountry" Group="GeoMap" />
<Field Type="Number" DisplayName="Latitude" Required="TRUE" ID="{EBFA40F7-A21A-4f4c-B941-036F5A360E0C}" SourceID="http://schemas.microsoft.com/sharepoint/v3" StaticName="MapLatitude" Name="MapLatitude" Group="GeoMap" />
<Field Type="Number" DisplayName="Longitude" Required="TRUE" ID="{ADDBDAC0-123C-46d5-9BA0-0D7EA29E5711}" SourceID="http://schemas.microsoft.com/sharepoint/v3" StaticName="MapLongitude" Name="MapLongitude" Group="GeoMap" />
<Field Type="Note" DisplayName="Additional Info" Required="FALSE" EnforceUniqueValues="FALSE" NumLines="6" RichText="FALSE" ID="{CDF90965-628A-4cf0-91E3-D6F3DBE233CC}" SourceID="http://schemas.microsoft.com/sharepoint/v3" StaticName="MapAdditionalInfo" Name="MapAdditionalInfo" Group="GeoMap" />
</Elements>

GeoMap List

GeoMap List is based on Generic List with GeoMap Content Type and with custom View

XSLT stylesheet for Map List View

<xsl:stylesheet xmlns:x="http://www.w3.org/2001/XMLSchema"
xmlns:d="http://schemas.microsoft.com/sharepoint/dsp"
version="1.0" exclude-result-prefixes="xsl msxsl ddwrt x d asp __designer SharePoint ddwrt2"
xmlns:ddwrt="http://schemas.microsoft.com/WebParts/v2/DataView/runtime"
xmlns:asp="http://schemas.microsoft.com/ASPNET/20"
xmlns:__designer="http://schemas.microsoft.com/WebParts/v2/DataView/designer"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:msxsl="urn:schemas-microsoft-com:xslt"
xmlns:SharePoint="Microsoft.SharePoint.WebControls"
xmlns:ddwrt2="urn:frontpage:internal">
<xsl:import href="/_layouts/xsl/main.xsl"/>
<xsl:output method="html" indent="no"/>
<xsl:template match="View[@BaseViewID='80']" mode="full" ddwrt:ghost="always">
<tr class="ms-viewheadertr"></tr>
<tr>
<td>
<div id="map_canvas" style="width:100%; height:480px"></div>
</td>
</tr>
<xsl:apply-templates mode="footer" select="." />
</xsl:template>
<xsl:template name="GeoMapViewOverride" mode="RootTemplate" match="View[List/@TemplateType=10488]" ddwrt:dvt_mode="root">
<script src="http://ajax.aspnetcdn.com/ajax/jquery/jquery-1.8.0.js"></script>
<script src="https://maps.googleapis.com/maps/api/js?v=3.exp&amp;sensor=false"></script>
<script src="/_layouts/spgeomap.js"></script>
<script type="text/javascript">
ExecuteOrDelayUntilScriptLoaded(initSPGeoMap, "sp.js");
</script>
<xsl:call-template name="View_Default_RootTemplate"/>
</xsl:template>
</xsl:stylesheet>

view raw
GeoMap.xsl
hosted with ❤ by GitHub

GeoMap rendering control

SP.GeoMapControl=function()
{
var _listId;
this.Init=function(listId)
{
_listId = listId;
loadMapData(function(entries){
if (entries==null)
{
alert('No Map data was found');
}
else
{
initMapControl(entries);
}
});
}
function initMapControl(mapEntries, params) {
var mapOptions = {
center: new google.maps.LatLng(34.397, 150.644),
zoom: 8,
mapTypeId: google.maps.MapTypeId.ROADMAP
};
var map = new google.maps.Map(document.getElementById("map_canvas"),mapOptions);
var infowindow = new google.maps.InfoWindow();
var bounds = new google.maps.LatLngBounds;
var i,marker;
for (i = 0; i < mapEntries.length; i++) {
var mapEntry = mapEntries[i];
var pos = new google.maps.LatLng(mapEntry.lat,mapEntry.lng);
marker = new google.maps.Marker({
map: map,
position: pos
});
google.maps.event.addListener(marker, 'click', (function(marker, i) {
return function() {
infowindow.setContent(mapEntries[i].content);
infowindow.open(map, marker);
}
})(marker, i));
bounds.extend(pos);
}
map.fitBounds(bounds);
}
function loadMapData(fnCallback) {
var context = new SP.ClientContext.get_current();
var web = context.get_web();
var listMap = web.get_lists().getById(_listId);
var viewXml = '<View><RowLimit>1200</RowLimit></View>';
var query = new SP.CamlQuery();
query.set_viewXml(viewXml);
var mapItems = listMap.getItems(query);
context.load(mapItems);
context.add_requestSucceeded(onMapLoaded);
context.add_requestFailed(onMapFailure);
context.executeQueryAsync();
function onMapLoaded() {
var mapsEntries=[];
var count=mapItems.get_count();
for (i=0 ; i < count; i++)
{
var mapItem=mapItems.itemAt(i);
var dataValues=mapItem.get_fieldValues();
var mapContent = '';
if(dataValues['MapAdditionalInfo'] != null)
mapContent = dataValues['MapAdditionalInfo'];
mapsEntries.push({ mapId: dataValues['ID'], title: dataValues['Title'], lat: dataValues['MapLatitude'], lng: dataValues['MapLongitude'],content: mapContent});
}
fnCallback(mapsEntries);
}
function onMapFailure() {
fnCallback(null);
}
}
};
function initSPGeoMap() {
var mapCtl = new SP.GeoMapControl();
mapCtl.Init(ctx.listName);
}

view raw
SPGeoMap.js
hosted with ❤ by GitHub

References

  • Google Maps JavaScript API v3
  • How to: Customize the Rendering of a Field on a List View in SharePoint 2010 on MSDN
  • How to: Customize a list view in apps for SharePoint using client-side rendering on MSDN

Customize the rendering of a List View in Sharepoint 2010: Displaying List Items in Accordion

Overview

The creation of non standard presentations for Lists/Libraries  is a fairly common  scenario and using the XSLT List View Web Part (XLV) possibilities that can be achieved pretty easily.
Let’s take a look how to render list of question and answers using Accordion Menu in SharePoint. Actually the idea for this post appeared after posting  of corresponding question on StackOverflow.
So, let’s discuss how it could be accomplished using XLV. For Accordion we will utilize jQuery UI library.

Accordion

Implementation

FAQ Custom List

First of all, let us define where  the questions and answers (FAQ) we’ll be stored. For this we will use Custom List with Content Type.

<ContentType ID="0x0100fb1027dc96a44bf280f6cb823a8da5ae"
Name="FAQ"
Group="SE"
Description="FAQ Content Type"
Inherits="TRUE"
Version="0">
<FieldRefs>
<FieldRef Name="LinkTitle" ID="{82642ec8-ef9b-478f-acf9-31f7d45fbc31}" DisplayName="Question" Sealed="TRUE"/>
<FieldRef Name="LinkTitleNoMenu" ID="{bc91a437-52e7-49e1-8c4e-4698904b2b6d}" DisplayName="Question" Sealed="TRUE"/>
<FieldRef Name="Title" ID="{fa564e0f-0c70-4ab9-b863-0177e6ddd247}" DisplayName="Question" Sealed="TRUE"/>
<FieldRef ID="{b0747420-54bc-41b2-a1b3-8432f2dbdc70}" Name="Answer"/>
</FieldRefs>
</ContentType>

view raw
FAQContentType.xml
hosted with ❤ by GitHub

Custom View for arranging items using jQuery UI Accordion

After creating Custom List we add new View for displaying Accordion for FAQ items

<View BaseViewID="10" Type="HTML" WebPartZoneID="Main" DisplayName="Accordion" DefaultView="FALSE" SetupPath="pages\viewpage.aspx" ImageUrl="/_layouts/images/generic.png" Url="Accordion.aspx">
<Toolbar Type="Standard" />
<XslLink Default="TRUE">FAQ.xsl</XslLink>
<RowLimit Paged="TRUE">30</RowLimit>
<ViewFields>
<FieldRef Name="Title" ID="{fa564e0f-0c70-4ab9-b863-0177e6ddd247}" DisplayName="Question" Sealed="TRUE"/>
<FieldRef Name="Answer" ID="{b0747420-54bc-41b2-a1b3-8432f2dbdc70}"></FieldRef>
</ViewFields>
<Query>
<OrderBy>
<FieldRef Name="ID"></FieldRef>
</OrderBy>
</Query>
<ParameterBindings/>
</View>

view raw
FAQAccordionView.xml
hosted with ❤ by GitHub

XSLT style sheet for rendering Accordion View

XSLT style sheet for FAQ List is intended for the following purposes:

  • loading jQuery Core and UI Libraries
  • rendering list items using layout as specified for Accordion menu
  • initializing and rendering Accordion for List items
<xsl:stylesheet xmlns:x="http://www.w3.org/2001/XMLSchema"
xmlns:d="http://schemas.microsoft.com/sharepoint/dsp"
version="1.0" exclude-result-prefixes="xsl msxsl ddwrt x d asp __designer SharePoint ddwrt2"
xmlns:ddwrt="http://schemas.microsoft.com/WebParts/v2/DataView/runtime"
xmlns:asp="http://schemas.microsoft.com/ASPNET/20"
xmlns:__designer="http://schemas.microsoft.com/WebParts/v2/DataView/designer"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:msxsl="urn:schemas-microsoft-com:xslt"
xmlns:SharePoint="Microsoft.SharePoint.WebControls"
xmlns:ddwrt2="urn:frontpage:internal">
<xsl:import href="/_layouts/xsl/main.xsl"/>
<xsl:output method="html" indent="no"/>
<xsl:template match="View[@BaseViewID='10']" mode="full" ddwrt:ghost="always">
<tr class="ms-viewheadertr"></tr>
<tr>
<td>
<div id="accordionFAQ">
<xsl:apply-templates select="." mode="RenderView" />
</div>
</td>
</tr>
<xsl:apply-templates mode="footer" select="." />
</xsl:template>
<xsl:template mode="Item" match="Row[../../@BaseViewID='10']" ddwrt:ghost="always">
<xsl:param name="Fields" select="."/>
<xsl:param name="Collapse" select="."/>
<xsl:param name="Position" select="1"/>
<xsl:param name="Last" select="1"/>
<xsl:variable name="thisNode" select="."/>
<h3>
<xsl:value-of select="$thisNode/@Title" />
</h3>
<div>
<xsl:value-of select="$thisNode/@Answer" disable-output-escaping="yes" />
</div>
</xsl:template>
<xsl:template name="FAQViewOverride" mode="RootTemplate" match="View[List/@TemplateType=11999]" ddwrt:dvt_mode="root">
<link rel="stylesheet" href="http://ajax.aspnetcdn.com/ajax/jquery.ui/1.8.10/themes/redmond/jquery-ui.css" />
<script src="http://ajax.aspnetcdn.com/ajax/jquery/jquery-1.8.0.js"></script>
<script src="http://ajax.aspnetcdn.com/ajax/jquery.ui/1.8.22/jquery-ui.js"></script>
<script>
$(function() {
$( "#accordionFAQ" ).accordion();
});
</script>
<xsl:call-template name="View_Default_RootTemplate"/>
</xsl:template>
</xsl:stylesheet>

view raw
FAQ.xsl
hosted with ❤ by GitHub

Using jQuery UI Accordion

jQuery Core and UI libraries are injected during XSLT style sheet processing. After JavaScript files which hosted on Microsoft CDN are loaded, jQuery UI Accordion is initialized for items.

<xsl:template name="FAQViewOverride" mode="RootTemplate" match="View[List/@TemplateType=11999]" ddwrt:dvt_mode="root">
<link rel="stylesheet" href="http://ajax.aspnetcdn.com/ajax/jquery.ui/1.8.10/themes/redmond/jquery-ui.css" />
<script src="http://ajax.aspnetcdn.com/ajax/jquery/jquery-1.8.0.js"></script>
<script src="http://ajax.aspnetcdn.com/ajax/jquery.ui/1.8.22/jquery-ui.js"></script>
<script>
$(function() {
$( "#accordionFAQ" ).accordion();
});
</script>
<xsl:call-template name="View_Default_RootTemplate"/>
</xsl:template>

view raw
FAQViewOverride.xsl
hosted with ❤ by GitHub

Results

FAQ List Accordion View rendered in XLV is shown below on picture

FAQ Accordion View

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. Part Two: Posting embedded code, support for different Video Providers, Preview view

Introduction

In previous post we have discussed  approach on how to embed video into SharePoint from YouTube. Custom List Video Links were used for storing embedded video properties and Computed Field for rendering Video player.
This time we will extend our solution with the following capabilities:

  • Support for different video providers listed in  oEmbed
  • Preview view for displaying video arranged in list
  • Alternative mode for posting the embed code for video into SharePoint

Support for different video providers

In addition to embed code using iframe, another options also available now. Some providers listed in oEmbed specification use object element for embedding code.

Table 1. Support for Video Providers listed in oEmbed specification

Provider Name Embedded Mode
YouTube IFrame, Object(YouTube)
Viddler
Qik Object(Qik)
Revision3 IFrame
Hulu IFrame
Vimeo IFrame
CollegeHumor Object(CollegeHumor)
Jest Object(Jest)
CircuitLab

Alternative mode for posting embedded code

Additionally to existing mode for embedding video code, the approach described below allows to paste the embed code as it was generated by Provider. Let’s take a look at the common usage scenario:

  • Generate and copy the embed code on the Provider website
  • Select Embed Code from New Item for Video Links List

  • In New Form for Video Links List paste the embed code and fill in comments if needed as shown below

For displaying video player the same (see previous post for details) Computed Field EmbeddedVideoOnForm field is used

Preview view for displaying video

In addition to default view (video player items with details), Preview view is intended to display items arranged by columns as shown below

Implementation

To paste the embed code we define Embed Code Content Type

<?xml version="1.0" encoding="utf-8"?>
<Elements xmlns="http://schemas.microsoft.com/sharepoint/">
<!– Parent ContentType: Link (0x0105) –>
<ContentType ID="0x010503"
Name="Embed Code"
Group="$Resources:List_Content_Types"
Description="Embed Code Content Type"
Inherits="FALSE"
Version="0">
<FieldRefs>
<FieldRef ID="{c29e077d-f466-4d8e-8bbe-72b66c5f205c}" Name="URL" Required="FALSE" Hidden="TRUE"/>
<FieldRef ID="{9F79BBE2-19A3-4341-96F6-BFDC024DEAB3}" Name="EmbedCode" Required="TRUE" />
</FieldRefs>
</ContentType>
</Elements>

where field EmbedCode for storing the embed code  is used

<Field ID="{9F79BBE2-19A3-4341-96F6-BFDC024DEAB3}"
Name="EmbedCode"
SourceID="http://schemas.microsoft.com/sharepoint/v3"
StaticName="EmbedCode"
Group="Media Columns"
Type="Note"
DisplayName="Embed Code"
Hidden="FALSE"
Sortable="FALSE">
</Field>

view raw
EmbedCode Field.xml
hosted with ❤ by GitHub

As was noted earlier, for displaying video player the same (see previous post for details) Computed Field EmbeddedVideoOnForm field is used, below is presented complete XSLT style sheet for  rendering of a field on a List View

<xsl:stylesheet xmlns:x="http://www.w3.org/2001/XMLSchema"
xmlns:d="http://schemas.microsoft.com/sharepoint/dsp"
version="1.0" exclude-result-prefixes="xsl msxsl ddwrt"
xmlns:ddwrt="http://schemas.microsoft.com/WebParts/v2/DataView/runtime"
xmlns:asp="http://schemas.microsoft.com/ASPNET/20"
xmlns:__designer="http://schemas.microsoft.com/WebParts/v2/DataView/designer"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:msxsl="urn:schemas-microsoft-com:xslt"
xmlns:SharePoint="Microsoft.SharePoint.WebControls"
xmlns:ddwrt2="urn:frontpage:internal">
<xsl:template name ="RenderEmbeddedPlayer" match ="FieldRef[@Name='EmbeddedVideoOnForm']" mode="Computed_body" >
<xsl:param name="thisNode" select="."/>
<xsl:variable name="width">
<xsl:call-template name="ensureVideoPlayerSize">
<xsl:with-param name="videoSize" select="$thisNode/@VideoWidth"/>
<xsl:with-param name="defaultSize" select="560"/>
</xsl:call-template>
</xsl:variable>
<xsl:variable name="height">
<xsl:call-template name="ensureVideoPlayerSize">
<xsl:with-param name="videoSize" select="$thisNode/@VideoHeight"/>
<xsl:with-param name="defaultSize" select="315"/>
</xsl:call-template>
</xsl:variable>
<xsl:variable name="frameborder">
<xsl:value-of select="$thisNode/@FrameBorder"/>
</xsl:variable>
<xsl:variable name="src">
<xsl:value-of select="$thisNode/@URL"/>
</xsl:variable>
<xsl:choose>
<xsl:when test="$thisNode/@EmbeddingMode ='IFrame'">
<iframe width="{$width}" height="{$height}" src="{$src}" frameborder="{$frameborder}" allowfullscreen=""></iframe>
</xsl:when>
<xsl:when test="$thisNode/@EmbeddingMode ='Object(YouTube)'">
<object width="{$width}" height="{$height}">
<param name="movie" value="{$src}"></param>
<param name="allowFullScreen" value="true"></param>
<param name="allowscriptaccess" value="always"></param>
<embed src="{$src}" type="application/x-shockwave-flash" width="{$width}" height="{$height}" allowscriptaccess="always" allowfullscreen="true"></embed>
</object>
</xsl:when>
<xsl:when test="$thisNode/@EmbeddingMode ='Object(Qik)'">
<object classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000" codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=9,0,115,0" width="{$width}" height="{$height}" align="middle">
<param name="allowScriptAccess" value="sameDomain" />
<param name="allowFullScreen" value="true" />
<param name="movie" value="{$src}" />
<param name="quality" value="high" />
<param name="bgcolor" value="#000000" />
<param name="FlashVars" value="streamID=9d0242b2912a444e84a31c2ca3249268&amp;autoplay=false" />
<embed src="{$src}" quality="high" bgcolor="#000000" width="{$width}" height="{$height}" name="qikPlayer" align="middle" allowScriptAccess="sameDomain" allowFullScreen="true" type="application/x-shockwave-flash" pluginspage="http://www.macromedia.com/go/getflashplayer" FlashVars="streamID=9d0242b2912a444e84a31c2ca3249268&amp;autoplay=false"></embed>
</object>
</xsl:when>
<xsl:when test="$thisNode/@EmbeddingMode ='Object(CollegeHumor)'">
<object type="application/x-shockwave-flash" data="{$src}" width="{$width}" height="{$height}">
<param name="allowfullscreen" value="true"/>
<param name="wmode" value="transparent"/>
<param name="allowScriptAccess" value="always"/>
<param name="movie" quality="best" value="{$src}"/>
<embed src="{$src}" type="application/x-shockwave-flash" wmode="transparent" width="{$width}" height="{$height}" allowScriptAccess="always"></embed>
</object>
</xsl:when>
<xsl:when test="$thisNode/@EmbeddingMode ='Object(Jest)'">
<object type="application/x-shockwave-flash" data="{$src}" width="{$width}" height="{$height}">
<param name="allowfullscreen" value="true"/>
<param name="wmode" value="transparent"/>
<param name="allowScriptAccess" value="always"/>
<param name="movie" quality="best" value="{$src}"/>
<embed src="{$src}" type="application/x-shockwave-flash" wmode="transparent" width="{$width}" height="{$height}" allowScriptAccess="always"></embed>
</object>
</xsl:when>
<xsl:otherwise>
<xsl:call-template name="renderEmbeddedCodeAsHtml">
<xsl:with-param name="embedId" select="$thisNode/@ID" />
<xsl:with-param name="embeddedCode" select="$thisNode/@EmbedCode" />
</xsl:call-template>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<xsl:template match ="FieldRef[@Name='EmbedCode']" ddwrt:dvt_mode="body" mode="Note_body">
<xsl:param name="thisNode" select="."/>
<div class="videolink-embedcode">
<xsl:value-of select="$thisNode/@EmbedCode" disable-output-escaping="yes" />
</div>
</xsl:template>
<xsl:template name="ensureVideoPlayerSize">
<xsl:param name="videoSize"/>
<xsl:param name="defaultSize"/>
<xsl:choose>
<xsl:when test="$videoSize &gt; 0">
<xsl:value-of select="$videoSize"/>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$defaultSize"/>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<xsl:template name="renderEmbeddedCodeAsHtml">
<xsl:param name="embedId"/>
<xsl:param name="embeddedCode"/>
<xsl:variable name="embeddedCodeUrl">
<xsl:value-of select="substring-before(substring-after($embeddedCode,'&gt;'),'&lt;/a&gt;')"/>
</xsl:variable>
<xsl:variable name="embeddedCodeFixed">
<xsl:value-of select="substring-before($embeddedCode,'&lt;a')"/>
<xsl:value-of select="$embeddedCodeUrl" />
<xsl:value-of select="substring-after($embeddedCode,'&lt;/a&gt;')"/>
</xsl:variable>
<xsl:variable name="embeddedCodeHtml">
<xsl:value-of select="$embeddedCodeFixed" disable-output-escaping="yes" />
</xsl:variable>
<div id="embeddedPlayerContainer{$embedId}">
</div>
<!–<xsl:value-of select="$embeddedCodeHtml" />–>
<script type="text/javascript">
var playerHost = 'embeddedPlayerContainer<xsl:value-of select="$embedId" />';
var player = '<xsl:value-of select="$embeddedCodeFixed" />';
<![CDATA[
player = player.replace(/&quot;/g, "'").replace(/&lt;/g, "<").replace(/&gt;/g, ">");
document.getElementById(playerHost).innerHTML = player;
]]>
</script>
</xsl:template>
</xsl:stylesheet>

References