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.

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

Overview

We have already discussed how to create Accordion List View in SharePoint 2010 in this post.
SharePoint 2013 introduces client side rendering framework for List View that allows to define the rendering logic of SharePoint list views using HTML/JavaScript. So, let’s discuss how to create Accordion List View in SharePoint 2013 based on client-side rendering.

For demonstration purposes we will create FAQ List based on Custom List. Default view for our list  will look like this

FAQDefaultView

And our goal here to customize it in such a way list items will be displayed  in accordion as shown below

AccordionListView

Implementation

In order to simplify our solution we restrict ourselves to the creation of client side rendering template only and applying it to the existing List View. If you are interested how to build custom solution for Accordion List  please follow my post about creating Accordion List View for SharePoint 2010.

Create Custom List for FAQ

FAQ List is based on Custom List. For storing questions we will utilize Title field, for Answers we will create new field with Note type

Create  client-side rendered view for Accordion

Client-side rendered view of an FAQ list is presented below

(function () {
loadCss('http://ajax.aspnetcdn.com/ajax/jquery.ui/1.8.10/themes/redmond/jquery-ui.css&#39;);
function OnAccordionViewPostRender(renderCtx) {
jQuery(function() {
jQuery( "#accordionFAQ" ).accordion();
});
}
function loadCss(url){
var link = document.createElement('link');
link.href = url;
link.rel = 'stylesheet';
document.getElementsByTagName('head')[0].appendChild(link);
}
function OnAccordionViewPreRender(renderCtx) {
}
function RenderAccordionViewBodyTemplate(renderCtx) {
var listData = renderCtx.ListData;
if (renderCtx.Templates.Body == '') {
return RenderViewTemplate(renderCtx);
}
var accordionHtml ='';
accordionHtml = '<div id="accordionFAQ">';
for (var idx in listData.Row) {
var listItem = listData.Row[idx];
accordionHtml += '<h3>';
accordionHtml += listItem.Title;
accordionHtml += '</h3>';
accordionHtml += '<div>';
accordionHtml += listItem.Answer;
accordionHtml += '</div>';
}
accordionHtml += '</div>';
return accordionHtml;
}
function _registerAccordionViewTemplate() {
var accordionViewContext = {};
//accordionViewContext.BaseViewID = 'Accordion';
accordionViewContext.Templates = {};
accordionViewContext.Templates.View = RenderAccordionViewBodyTemplate;
accordionViewContext.OnPreRender = OnAccordionViewPreRender;
accordionViewContext.OnPostRender = OnAccordionViewPostRender;
SPClientTemplates.TemplateManager.RegisterTemplateOverrides(accordionViewContext);
}
ExecuteOrDelayUntilScriptLoaded(_registerAccordionViewTemplate, 'clienttemplates.js');
})();

Customize a List View

The last step is to apply client-side rendering template to existing view. Let’s first add FAQ List instance on on page, after that  we only need to specify JSLink property value for List View

Please note that actually  three JavaScript files have been specified(the first two are jQuery libraries) for  JSLink property. All of them are stored in my case in hive, but of course they could be stored not only in file system.