Friday, June 29, 2012

Copy Slides to Presentation outside of Slide Library Context

Slide Library is a powerful document management feature of SharePoint 2010 but still very much underutilized. You can publish slides from you local machine to this library directly. Slides are stored as .pptx files. To do this. right click the ppt and click "Publish slides" and enter the slide library URL in the address box. This is fairly easy to do and very useful for someone who wants to publish only parts of their ppt file.

The another important feature of Slide Library is the "Copy Slides to Presentation". You can select the slides from the library and on click of the "Copy Slides to Presentation" button it will create a new presentation with the selected slides or it will add to a existing presentation based on your selection.  

This is a very cool feature that I wanted to use in my custom webparts and in some other pages. "Copy Slides to Presentation" button is a activex control embedded in the slides library. I was digging into how this is working. I was looking at the sharepoint js files and found that 1033/SLDLIB.js is the file that is called when you click the button. If you look at the file they get the pptx file URLs and form a array and pass it to the active control. I tried to replicate the same in my custom webpart and it worked amazingly!

1. First add the below reference to the js file 
  <script type="text/javascript" src="/_layouts/1033/SLDLIB.js"></script>
2. Place the Activex Control in the page as below.

<object id="ppactivex" 
classid="clsid:99098758-CB85-4a90-924F-F21898796281" style="visibility:hidden" OnError="SetActiveXStatus(false);">
</object>

3.Copy the below vbscript function to the page.

<script type="text/vbscript">
function CallInsertSlides(Selected)
    arrSelected = Split(Selected, ",", -1, 0)
    set objx = Document.ppactivex
    objx.InsertSlidesFromSlideLibrary arrSelected
End function
</script>

4. Now just call the CallInsertSlides function from you javascript code as below

CallInsertSlides("/Slides%20Management/sureshtest.pptx");

In the above function I have passed only one URL. You can form a array of URLs from the items selected and pass it to the function as below. 

.S4-itm-cbx is the class of the checkboxes in the page.

$(".s4-itm-cbx:checked").each(function () {
            var parentcell = $(this).parent();
            var hyperlinkparent = $(parentcell).next().next().children();
            selItems[cSelectedSlides++] = GetEscapedUrl(portalurl + $(hyperlinkparent).attr("href"));           
        });

CallInsertSlides(selItems);
When the function CallInsertSlides is called it will open a dialog box to copy the presentation.
Happy coding !!!!.


Update: Below is the entire sample aspx page I have created as there were requests to provide the sample.




<%@ Assembly Name="Microsoft.SharePoint, Version=14.0.0.0, Culture=neutral,

PublicKeyToken=71e9bce111e9429c"%> <%@ Page Language="C#"

Inherits="Microsoft.SharePoint.WebPartPages.WikiEditPage"

MasterPageFile="~masterurl/default.master" meta:progid="SharePoint.WebPartPage.Document"

meta:webpartpageexpansion="full"       %>
<%@ Import Namespace="Microsoft.SharePoint.WebPartPages" %> <%@ Register

Tagprefix="SharePoint" Namespace="Microsoft.SharePoint.WebControls"

Assembly="Microsoft.SharePoint, Version=14.0.0.0, Culture=neutral,

PublicKeyToken=71e9bce111e9429c" %> <%@ Register Tagprefix="Utilities"

Namespace="Microsoft.SharePoint.Utilities" Assembly="Microsoft.SharePoint, Version=14.0.0.0,

Culture=neutral, PublicKeyToken=71e9bce111e9429c" %> <%@ Import

Namespace="Microsoft.SharePoint" %> <%@ Assembly Name="Microsoft.Web.CommandUI,

Version=14.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>
<%@ Register Tagprefix="WebPartPages" Namespace="Microsoft.SharePoint.WebPartPages"

Assembly="Microsoft.SharePoint, Version=14.0.0.0, Culture=neutral,

PublicKeyToken=71e9bce111e9429c" %>
<asp:Content ContentPlaceHolderId="PlaceHolderPageTitle" runat="server">
<SharePoint:ProjectProperty Property="Title" runat="server"/> -
<SharePoint:ListItemProperty runat="server"/>
</asp:Content>
<asp:Content ContentPlaceHolderId="PlaceHolderPageTitleInTitleArea" runat="server">
<span>
<SharePoint:DocumentFolderName runat="server" id="PageFolderName"

AppendSeparatorArrow = "true"/>
</span>
<span class="ms-WikiPageNameEditor-Display" id="wikiPageNameDisplay" runat="server">
<SharePoint:ListItemProperty runat="server"/>
</span>
<span class="ms-WikiPageNameEditor-Edit" style="display:none;" id="wikiPageNameEdit"

runat="server">
<asp:TextBox id="wikiPageNameEditTextBox" runat="server"/>
</span>
</asp:Content>
<asp:Content ContentPlaceHolderId="PlaceHolderPageDescription" runat="server">
<SharePoint:UIVersionedContent runat="server" UIVersion="4">
<ContentTemplate>
<SharePoint:ProjectProperty Property="Description" runat="server"/>
</ContentTemplate>
</SharePoint:UIVersionedContent>
</asp:Content>
<asp:Content ContentPlaceHolderId="PlaceHolderPageImage" runat="server">
<SharePoint:AlphaImage ID=onetidtpweb1 Src="/_layouts/images/wiki.png" Width=145

Height=54 Alt="" Runat="server"/></asp:Content>
<asp:Content ContentPlaceHolderId="PlaceHolderAdditionalPageHead" runat="server">


<script type="text/javascript"></script>

<meta name="CollaborationServer" content="SharePoint Team Web Site" />
<script type="text/javascript">
var navBarHelpOverrideKey = "WSSEndUser";
</script>
<SharePoint:RssLink runat="server"/>
<SharePoint:UIVersionedContent UIVersion="4" runat="server"><ContentTemplate>
<SharePoint:CssRegistration runat="server" Name="wiki.css" />
</ContentTemplate></SharePoint:UIVersionedContent>
</asp:Content>
<asp:Content ContentPlaceHolderId="PlaceHolderMiniConsole" runat="server">
<SharePoint:FormComponent TemplateName="WikiMiniConsole" ControlMode="Display"

runat="server" id="WikiMiniConsole"/>
</asp:Content>
<asp:Content ContentPlaceHolderId="PlaceHolderLeftActions" runat="server">
<SharePoint:RecentChangesMenu runat="server" id="RecentChanges"/>
</asp:Content>
<asp:Content ContentPlaceHolderId="PlaceHolderMain" runat="server">



<SharePoint:UIVersionedContent runat="server" UIVersion="3"

Id="PlaceHolderWebDescription">
<ContentTemplate>
<div class="ms-webpartpagedescription"><SharePoint:ProjectProperty

Property="Description" runat="server"/></div>
</ContentTemplate>
</SharePoint:UIVersionedContent>
<asp:UpdatePanel
  id="updatePanel"
  runat="server"
  UpdateMode="Conditional"
  ChildrenAsTriggers="false">
<ContentTemplate>
<SharePoint:VersionedPlaceHolder UIVersion="4" runat="server">
<SharePoint:SPRibbonButton
id="btnWikiEdit"


RibbonCommand="Ribbon.WikiPageTab.EditAndCheckout.SaveEdit.Menu.SaveEdit.Edit"
runat="server"
   Text="edit"/>
<SharePoint:SPRibbonButton
id="btnWikiSave"


RibbonCommand="Ribbon.WikiPageTab.EditAndCheckout.SaveEdit.Menu.SaveEdit.SaveAndStop"
runat="server"
   Text="edit"/>
<SharePoint:SPRibbonButton
id="btnWikiRevert"


RibbonCommand="Ribbon.WikiPageTab.EditAndCheckout.SaveEdit.Menu.SaveEdit.Revert"
   runat="server"
Text="Revert"/>
</SharePoint:VersionedPlaceHolder>
<SharePoint:EmbeddedFormField id="WikiField" FieldName="WikiField"

ControlMode="Display" runat="server"></SharePoint:EmbeddedFormField>
<WebPartPages:WebPartZone runat="server" ID="Bottom"

Title="loc:Bottom"><ZoneTemplate></ZoneTemplate></WebPartPages:WebPartZone>
</ContentTemplate>
<Triggers>
   <asp:PostBackTrigger ControlID="WikiField" />
   <asp:PostBackTrigger ControlID="btnWikiRevert" />
   <asp:PostBackTrigger ControlID="btnWikiSave" />
</Triggers>
 </asp:UpdatePanel>
 <script type="text/javascript" src="/_layouts/lazard/scripts/jquery-1.7.2.js"></script>
  <script type="text/javascript" src="/_layouts/lazard/1033/SLDLIB.js"></script>
<script type="text/javascript">

$(document).ready(function(){
        CallInsertSlides(serverurl+"/Slides%20Management/sureshtest.pptx");
});

   


</script>
<script type="text/vbscript">
function CallInsertSlides(Selected)
    arrSelected = Split(Selected, ",", -1, 0)
    set objx = Document.ppactivex
    objx.InsertSlidesFromSlideLibrary arrSelected
End function
</script>

<input type="button" value="Copy to presentation slides" onclick="javascript:CallPPT();">
<object id="ppactivex"
classid="clsid:99098758-CB85-4a90-924F-F21898796281" style="visibility:hidden"

OnError="SetActiveXStatus(false);">
</object>

</asp:Content>

7 comments:

  1. I created page and place the code same above step using content editor but i got the following error when saving the page

    No such interface supported
    Line: 2
    Char: 176093
    Code: 0
    URI: https://connect.joneslanglasalle.com/_layouts/sp.ui.rte.js?rev=shRwEXLi7dBePz9i1Zw7TQ%3D%3D

    beacuase of adding (classid="clsid:99098758-CB85-4a90-924F-F21898796281")

    Please help to resolve this

    ReplyDelete
  2. Instead of trying it in a content editor webpart, just create a new aspx page and try it. Make sure that you insert the activex control and a reference to SLDLIB.js

    ReplyDelete
  3. Thank you for writing this up Suresh. I'm trying to use the method above in a DVWP I created, but I'm hitting a wall. Each slide has a checkbox where I am attempting to pass either the URL or the ID. I can easily create a snippet in javascript that loops through all selected checkboxes and passes their value into the array, but I'm getting a disconnect when I try to pass those values to the default functions in SLDLIB.

    ReplyDelete
  4. Did you include this ppactivex object in your page?

    ReplyDelete
    Replies
    1. Yes - I have a reference to the JQuery library in my master pages, and then I've added the reference to SLDLIB.js, the ActiveX object, and the VBscript snippet to the actual webpart code (just before the table tag in the dvt_1 template). My Javascript appears to be working ok, as when I click the "Add slides" button it correctly counts the number of selected checkboxes and shows me the count in a message box. When calling the CallInsertSlides function, I consistently get an "Object expected" error, so I think the array values aren't passing to the VBscript correctly. I could be wrong, though - I'm only a weekend developer so far.

      Delete
    2. I'm making progress - I now have the array values passing to the VBscript (had to convert my JS array to a string first). The problem I'm running into now is that the VBscript isn't recognizing the ppactivex object and/or the EnsurePPPlugin function in SLDLIB is returning a NULL value for it. I've tried declaring the value directly but that isn't working either for some reason.

      I'll get there eventually, but was wondering if you had run into any similar issues...

      Delete
    3. Hi,

      I remember CallInsertSlides did not work in some pages. One of the workaround is create a wrapper page with the code that accepts the ppt names in the querystring and you can call this page on your webpart.

      Thanks
      Suresh

      Delete