Saturday, May 9, 2015

Add or Replace Existing Publishing Page Web Parts with SharePoint App Parts using App Model Approach (Provider Hosted)

The below code is tested and i am able to add app parts to the existing publishing page.

In Publishing Page the web parts can also be added in "PublishingPageContent" and "RichHTMLField"

if you are migrating from SharePoint 2010 custom web parts to App Parts which has lot of work around. especially in the case of existing publishing page which has lot of custom web parts, we cant get the zone id properly.  

Use the below code to add app part to the existing publishing page. However we could replace the existing web part with app part using web part id. 

protected void ReplaceWebPartsWithAppParts_Click(object sender, EventArgs e)
        {
            var spContext = SharePointContextProvider.Current.GetSharePointContext(Context);
            using (var clientContext = spContext.CreateUserClientContextForSPHost())
            {
                PublishingWeb publishingWeb = PublishingWeb.GetPublishingWeb(clientContext, clientContext.Web);
                // Get a few properties from the web
                clientContext.Load(publishingWeb);
                clientContext.ExecuteQuery();
                //Read the pages library name from the web properties
                //var pagesListName = web.AllProperties["Pages"] as string;
                var list = publishingWeb.Web.Lists.GetByTitle("Pages");
                var items = list.GetItems(CamlQuery.CreateAllItemsQuery());
                //make sure to include the File on each Item fetched
                clientContext.Load(items,
                                   i => i.Include(item => item.File, item => item["PublishingPageContent"]));
                clientContext.ExecuteQuery();
                // Iterate through all available pages in the pages list
                foreach (var item in items)
                {
                    FindWebPartForReplacement(item, clientContext, clientContext.Web);
                }
            }
        }




 private static void FindWebPartForReplacement(ListItem item, ClientContext clientContext, Web web)
        {
            PublishingPage publishingPage = PublishingPage.GetPublishingPage(clientContext, item);

            clientContext.Load(publishingPage);
            clientContext.ExecuteQuery();

            File page = publishingPage.ListItem.File;

            // Requires Full Control permissions on the Web
            LimitedWebPartManager webPartManager = publishingPage.ListItem.File.GetLimitedWebPartManager(PersonalizationScope.Shared);
            clientContext.Load(webPartManager,
                                wpm => wpm.WebParts,
                                wpm => wpm.WebParts.Include(wp => wp.WebPart.Title));
            clientContext.ExecuteQuery();

            foreach (var oldWebPartDefinition in webPartManager.WebParts)
            {
                var oldWebPart = oldWebPartDefinition.WebPart;
                // only modify if we find the old web part
                if (oldWebPart.Title != oldWebPartTitle) continue;

                // Check out the page for editing
                PublishingHelper.CheckOutFile(web, publishingPage.ListItem);

                // transform the xml into a web part definition
                WebPartDefinition definition = webPartManager.ImportWebPart(appPartXml);
                webPartManager.AddWebPart(definition.WebPart, "wpz", 0);

                clientContext.Load(webPartManager,
                                  wpm => wpm.WebParts,
                                  wpm => wpm.WebParts.Include(wp => wp.WebPart.TitleUrl, wp => wp.Id, wp => wp.WebPart.Title));
                clientContext.ExecuteQuery();

                string marker = string.Empty;
                int i = 0;
                foreach (WebPartDefinition wpd in webPartManager.WebParts)
                {
                    Guid storageKey = webPartManager.WebParts[i].Id;

                    if (wpd.WebPart.Title == "WelcomeAppPart Title")
                    {
                        clientContext.Load(publishingPage, p => p.ListItem, p => p.ListItem["PublishingPageContent"]);
                        clientContext.ExecuteQuery();

                        marker = String.Format(CultureInfo.InvariantCulture, "<div class=\"ms-rtestate-read ms-rte-wpbox\" contentEditable=\"false\"><div class=\"ms-rtestate-notify ms-rtestate-read {0}\" id=\"div_{0}\"></div><div style=\"display:none\" id=\"vid_{0}\"></div></div>", new object[] { storageKey.ToString("D") });
                        publishingPage.ListItem["PublishingPageContent"] += marker;
                        publishingPage.ListItem.Update();
                    }
                    i++;
                }

                clientContext.Load(page, p => p.CheckOutType, p => p.Level);
                clientContext.ExecuteQuery();
                PublishingHelper.CheckInPublishAndApproveFile(page);
                break;
            }
        }

Tuesday, January 6, 2015

SharePoint Workflow Association to SharePoint List

The below code is used to associate the workflow to the list as well as the update the workflow association to the sharepoint list

 // Add workflow association to my list
                        if (hasWorkflowAssociation == null)
                        {
                            sharePointSitesList.WorkflowAssociations.Add(workflowAssociation);
                            // Enable workflow
                            workflowAssociation.Enabled = true;
                        }
                        else
                        {
                            hasWorkflowAssociation.Enabled = true;
                            sharePointSitesList.UpdateWorkflowAssociation(hasWorkflowAssociation);
                            sharePointSitesList.Update();
                        }

Monday, December 15, 2014

Office 365/ SharePoint Online / SharePoint hosted App - Custom Action ScriptLink

Step1: Added button in Default.aspx page
    <input type="button" value="Add Custom Ribbon" title="Add" onclick="AddCustomAction();" />

Step2: Written the below script for "AddCustomAction" method
This method performs 2 operations
1) Add script link ie," test.js "
2) Add custom ribbon tab only for template type 10000

function AddCustomAction() {
    var context = new SP.ClientContext.get_current;
    this.oWebsite = context.get_web();
    var collUserCustomAction = this.oWebsite.get_userCustomActions();
    var scriptLink = collUserCustomAction.add();
    scriptLink.set_name('Welcomescriptlink');
    scriptLink.set_title('Welcome');
    scriptLink.set_description('Welcome to new custom script Link');
    scriptLink.set_location('ScriptLink');
    scriptLink.set_scriptSrc('~Site/Scripts/test.js');
    scriptLink.set_group('');
    scriptLink.update();

    var oUserCustomAction = collUserCustomAction.add();
    oUserCustomAction.set_name('Welcome');
    oUserCustomAction.set_title('Welcome Title');
    oUserCustomAction.set_description('Welcome to new custom Action');
    oUserCustomAction.set_location('CommandUI.Ribbon');
    oUserCustomAction.set_registrationId('10000');
    oUserCustomAction.set_registrationType(1);
    oUserCustomAction.set_group('');
    var ca = '<CommandUIExtension xmlns="http://schemas.microsoft.com/sharepoint/">' +
  '<CommandUIDefinitions>' +
    '<CommandUIDefinition Location="Ribbon.Tabs._children">' +
      '<Tab Id="Demo.Tab" Title="SLK Utilities" Description="SLK Utilities" Sequence="10000">' +
        '<Scaling Id="Demo.Tab.Scaling">' +
          '<MaxSize Id="Demo.Tab.Group.Scaling.MaxSize" GroupId="Demo.Tab.Group" Size="LargeLarge" />' +
          '<Scale Id="Demo.Tab.Group.Scaling.Scale" GroupId="Demo.Tab.Group" Size="LargeLarge" />' +
        '</Scaling>' +
        '<Groups Id="Demo.Tab.Groups">' +
          '<Group Id="Demo.Tab.Group" Title="Print" Description="Print the selected items" Template="Ribbon.Templates.Flexible2">' +
            '<Controls Id="Demo.Tab.Group.Controls">' +
              '<Button Id="DemoControlID" LabelText="" ToolTipTitle="Print" ToolTipDescription="Print the selected items" Command="DemoControlID.Command" TemplateAlias="o1" Image32by32="~site/images/printer.png" />' +
            '</Controls>' +
          '</Group>' +
        '</Groups>' +
      '</Tab>' +
    '</CommandUIDefinition>' +
    '<CommandUIDefinition Location="Ribbon.Templates._children">' +
      '<GroupTemplate Id="Ribbon.Templates.Flexible2">' +
       '<Layout Title="LargeLarge">' +
              '<OverflowSection Type="OneRow" TemplateAlias="o1" DisplayMode="Large"/>' +
              '<OverflowSection Type="OneRow" TemplateAlias="o2" DisplayMode="Large"/>' +
        '</Layout>' +
      '</GroupTemplate>' +
    '</CommandUIDefinition>' +
  '</CommandUIDefinitions>' +
  '<CommandUIHandlers>' +
    '<CommandUIHandler Command="DemoControlID.Command" CommandAction="javascript:SP.UI.ModalDialog.showModalDialog({url:\'{SiteUrl}/Pages/Demo.aspx?{StandardTokens}&amp;SPListItemId={ItemId}&amp;SPListId={ListId}\', title:\'Page Title\'});"/>' +
  '</CommandUIHandlers>' +
'</CommandUIExtension>';
    oUserCustomAction.set_commandUIExtension(ca)
    oUserCustomAction.update();
    context.load(this.oWebsite, 'Title', 'UserCustomActions');
    context.executeQueryAsync(Function.createDelegate(this, this.onQuerySucceeded), Function.createDelegate(this, this.onQueryFailed));
}

function onQuerySucceeded() {
    alert('Custom action created for ' + this.oWebsite.get_title());
}

function onQueryFailed(sender, args) {
    alert('Request failed. ' + args.get_message() + '\n' + args.get_stackTrace());
}


Step3: The below script i have written for " test.js " file.

var url = window.location.pathname;

if (url.toString().toLowerCase().indexOf("lists") > -1) {
    var path = url.substring(url.toString().toLowerCase().indexOf("lists"), url.length);
    var pathArray = path.split('/');
    var listName = pathArray[1];

    ExecuteOrDelayUntilScriptLoaded(retrieveWebSite, "sp.js");

    var oWebsite;
    var list;
    var viewCollection;

    function retrieveWebSite() {
        var clientContext = new SP.ClientContext.get_current();
        oWebsite = clientContext.get_web();
        list = oWebsite.get_lists().getByTitle(listName);
        viewCollection = list.get_views();
        clientContext.load(list);
        clientContext.load(viewCollection);
        clientContext.executeQueryAsync(Function.createDelegate(this, this.onQuerySucceededs), Function.createDelegate(this, this.onQueryFaileds));
    }

    function onQuerySucceededs() {
        if (list.get_baseTemplate() == "10000") {
            var viewEnumerator = viewCollection.getEnumerator();
            while (viewEnumerator.moveNext()) {
                var currentView = viewEnumerator.get_current();
                if (currentView.get_serverRelativeUrl().toString().toLowerCase() == url.toString().toLowerCase()) {
                    SP.UI.Notify.addNotification("<span>List Title " + list.get_title() + "<\/span>");
                    var selection = SP.ListOperation.Selection.getSelectedItems(list.get_context());
                }
            }
        }
    }

    function onQueryFaileds(sender, args) {
        alert('Request failed. ' + args.get_message() + '\n' + args.get_stackTrace());
    }
}

Question:

My question is, how i can optimize the above test.js script such a way that it will execute only for template type 10000 instead of doing so many if , while checks here and executing for other lists. I would like to know if there is any other way to implement this.

Basically my task is, onclick of button i have to register and enable the custom ribbon tab ( in app web )

Thursday, December 11, 2014

Add custom ribbon tab in app web using javascript/ecmascript and open the page in modal dialog . SharePoint 2013/Office 365

Hello All,

Today i am going to show how to add a custom ribbon tab in app web using javascript. Please refer the below code for adding custom ribbon tab and open the page using SharePoint Modal Dialog


function AddCustomAction() {
    var context = new SP.ClientContext.get_current;

    this.oWebsite = context.get_web();
    var collUserCustomAction = this.oWebsite.get_userCustomActions();

    var oUserCustomAction = collUserCustomAction.add();
    oUserCustomAction.set_name('Welcome');
    oUserCustomAction.set_title('Welcome Title');
    oUserCustomAction.set_description('Welcome to new custom Action');
    oUserCustomAction.set_location('CommandUI.Ribbon');
    oUserCustomAction.set_registrationId('101');
    oUserCustomAction.set_registrationType(1);
    oUserCustomAction.set_group('');


    var ca = '<CommandUIExtension xmlns="http://schemas.microsoft.com/sharepoint/">' +
  '<CommandUIDefinitions>' +
    '<CommandUIDefinition Location="Ribbon.Tabs._children">' +
      '<Tab Id="Demo.Tab" Title="Utilities" Description="Utilities" Sequence="10000">' +
        '<Scaling Id="Demo.Tab.Scaling">' +
          '<MaxSize Id="Demo.Tab.Group.Scaling.MaxSize" GroupId="Demo.Tab.Group" Size="LargeLarge" />' +
          '<Scale Id="Demo.Tab.Group.Scaling.Scale" GroupId="Demo.Tab.Group" Size="LargeLarge" />' +
        '</Scaling>' +
        '<Groups Id="Demo.Tab.Groups">' +
          '<Group Id="Demo.Tab.Group" Title="Print" Description="Print the selected items" Template="Ribbon.Templates.Flexible2">' +
            '<Controls Id="Demo.Tab.Group.Controls">' +
              '<Button Id="DemoControlID" LabelText="" ToolTipTitle="Print" ToolTipDescription="Print the selected items" Command="DemoControlID.Command" TemplateAlias="o1" Image32by32="~site/images/printer.png"/>' +
            '</Controls>' +
          '</Group>' +
        '</Groups>' +
      '</Tab>' +
    '</CommandUIDefinition>' +
    '<CommandUIDefinition Location="Ribbon.Templates._children">' +
      '<GroupTemplate Id="Ribbon.Templates.Flexible2">' +
        '<Layout Title="LargeLarge" LayoutTitle="LargeLarge">' +
          '<OverflowSection DisplayMode="Large" TemplateAlias="o1" Type="OneRow" />' +
          '<OverflowSection DisplayMode="Large" TemplateAlias="o2" Type="OneRow" />' +
        '</Layout>' +
        '<Layout Title="LargeMedium" LayoutTitle="LargeMedium">' +
          '<OverflowSection DisplayMode="Large" TemplateAlias="o1" Type="OneRow" />' +
          '<OverflowSection DisplayMode="Medium" TemplateAlias="o2" Type="ThreeRow" />' +
        '</Layout>' +
        '<Layout Title="LargeSmall" LayoutTitle="LargeSmall">' +
          '<OverflowSection DisplayMode="Large" TemplateAlias="o1" Type="OneRow" />' +
          '<OverflowSection DisplayMode="Small" TemplateAlias="o2" Type="ThreeRow" />' +
        '</Layout>' +
        '<Layout Title="MediumLarge" LayoutTitle="MediumLarge">' +
          '<OverflowSection DisplayMode="Medium" TemplateAlias="o1" Type="ThreeRow" />' +
          '<OverflowSection DisplayMode="Large" TemplateAlias="o2" Type="OneRow" />' +
        '</Layout>' +
        '<Layout Title="MediumMedium" LayoutTitle="MediumMedium">' +
          '<OverflowSection DisplayMode="Medium" TemplateAlias="o1" Type="ThreeRow" />' +
          '<OverflowSection DisplayMode="Medium" TemplateAlias="o2" Type="ThreeRow" />' +
        '</Layout>' +
        '<Layout Title="MediumSmall" LayoutTitle="MediumSmall">' +
          '<OverflowSection DisplayMode="Medium" TemplateAlias="o1" Type="ThreeRow" />' +
          '<OverflowSection DisplayMode="Small" TemplateAlias="o2" Type="ThreeRow" />' +
        '</Layout>' +
        '<Layout Title="SmallLarge" LayoutTitle="SmallLarge">' +
          '<OverflowSection DisplayMode="Small" TemplateAlias="o1" Type="ThreeRow" />' +
          '<OverflowSection DisplayMode="Large" TemplateAlias="o2" Type="OneRow" />' +
        '</Layout>' +
        '<Layout Title="SmallMedium" LayoutTitle="SmallMedium">' +
          '<OverflowSection DisplayMode="Small" TemplateAlias="o1" Type="ThreeRow" />' +
          '<OverflowSection DisplayMode="Medium" TemplateAlias="o2" Type="ThreeRow" />' +
        '</Layout>' +
        '<Layout Title="SmallSmall" LayoutTitle="SmallSmall">' +
          '<OverflowSection DisplayMode="Small" TemplateAlias="o1" Type="ThreeRow" />' +
          '<OverflowSection DisplayMode="Small" TemplateAlias="o2" Type="ThreeRow" />' +
        '</Layout>' +
      '</GroupTemplate>' +
    '</CommandUIDefinition>' +
  '</CommandUIDefinitions>' +
  '<CommandUIHandlers>' +
    '<CommandUIHandler Command="DemoControlID.Command" CommandAction="javascript:SP.UI.ModalDialog.showModalDialog({url:\'{SiteUrl}/Pages/Demo.aspx?{StandardTokens}&amp;SPListItemId={ItemId}&amp;SPListId={ListId}\', title:\'Page Title\'});"/>' +
  '</CommandUIHandlers>' +
'</CommandUIExtension>';

    oUserCustomAction.set_commandUIExtension(ca)
    oUserCustomAction.update();

    context.load(this.oWebsite, 'Title', 'UserCustomActions');

    context.executeQueryAsync(Function.createDelegate(this, this.onQuerySucceededs), Function.createDelegate(this, this.onQueryFaileds));
}

function onQuerySucceededs() {

    alert('Custom action created for ' + this.oWebsite.get_title());
}

function onQueryFaileds(sender, args) {

    alert('Request failed. ' + args.get_message() + '\n' + args.get_stackTrace());
}

Monday, August 25, 2014

__REQUESTDIGEST is undefined in sharepoint hosted app ( Client WebPart ) but its working in full page app

Below is the way to use. Note its working in both Single Page App and Client App Part as well

var formDigest; //Declare the variable
//Document Ready
$(document).ready(function () {
    hostweburl = decodeURIComponent(getQueryStringParameter('SPHostUrl'));
    appweburl = decodeURIComponent(getQueryStringParameter('SPAppWebUrl'));
    scriptbase = hostweburl + '/_layouts/15/';
    CharacterAnimation();
    $.getScript(scriptbase + 'SP.Runtime.js', function ()
    {
        $.getScript(scriptbase + 'SP.js', function ()
        {
            $.getScript(scriptbase + 'SP.RequestExecutor.js', getFormDigest);
        });
    });
});
//Get  Form Digest Value
function getFormDigest() {
    var appweburl = decodeURIComponent(getQueryStringParameter('SPAppWebUrl'));
    $.ajax({
        url: appweburl + "/_api/contextinfo",
        type: "POST",
        headers: {
            "accept": "application/json;odata=verbose",
            "contentType": "text/xml"
        },
        success: function (data) {
            requestdigest = data;
            var formDigest = data.d.GetContextWebInformation.FormDigestValue;
            DoSomething(formDigest);
        },
        error: function (err) {
            alert(JSON.stringify(err));
        }
    });
}
//Do Something Method
function  DoSomething(formDigest) {
    var urltest = appweburl + "/_api/SP.AppContextSite(@target)/web/lists/getByTitle('List1')/getitems(<Query><Where><BeginsWith><FieldRef">query=@v1)?@v1={\"ViewXml\":\"<View><Query><Where><BeginsWith><FieldRef Name='Title'/><Value Type='Text'>A</Value></BeginsWith></Where></Query><RowLimit>1</RowLimit></View>\"}&@target='" + hostweburl + "'";
    $.ajax({
        url: urltest,
        type: "POST",
        headers: {
            "Accept": "application/json; odata=verbose",
            "Content-Type": "application/json; odata=verbose",
            "X-RequestDigest": formDigest
        },
        contentType: 'application/json',
        success: function (data) {
            alert(data); // Finally found [Object][Object] :)
        },
        error: function (data) {
            alert(data.responseText);
        }
    });
}

Wednesday, May 14, 2014

publishing page content returns unclosed html tags and unicode characters sharepoint 2013

I was writing a console application in SharePoint 2013 to fetch the content of PublishingPageContent in wiki page.

I had converted the page from Word document to Web page using SharePoint 2013 OOTB "Convert To" option in Wiki Site.

However , When i fetch the content of PublishingPageContent it returns unicode characters and unclosed html tags in SharePoint 2013 which is unexpected. 

The same is working perfectly in SharePoint 2010. Not sure why this change happened in SharePoint 2013. 

This is strange in SharePoint 2013 wiki site.


Sample HTML with unclosed html tags and unicode characters

 Resolution:

After a month of research found and answer with HTMLSANITIZER. Refer the below link

This helped in fixing the above issue. I hope this information helps someone else. :)