SharePoint 2013 Execute Javascript function after MDS load

SharePoint 2013 introduces a performance improvement to increase the page load response time called Minimal Download Strategy (MDS). It is a feature that by default is activated in the team site. The MDS is performed by functions inside javascript file called start.js. This blog explains the flow of a MDS call.

So it is a bit tricky to execute a javascript function to modify the DOM after the MDS finish as a normal jQuery’s document.ready function or¬†_spBodyOnLoadFunctionNames are executed before the MDS script finishes.

Inside the start.js file there is an object called asyncDeltaManager that perform most of the async page loading. After several times code stepping in a javascript debugger, I could see what is going on under the hood, at the end the process a function called _scriptsLoadComplete is called and inside it, a function called _endRequest is called. And in the _endRequest function there is a routine to iterate a eventHandlerList called endRequest. So there is a event handler that we can hook our function into the asyncDeltaManager pipeline. Shortly, below code shows how to perform this task.

$(function () {
      ExecuteOrDelayUntilScriptLoaded(function () {
          if (typeof asyncDeltaManager != "undefined")
            asyncDeltaManager.add_endRequest(setFullScreenMode);
          else setFullScreenMode();
      }, "start.js");

  });

function setFullScreenMode() {
     SetFullScreenMode(true);
     $('#siteactiontd').hide();
     PreventDefaultNavigation();
     $('#fullscreenmodebox').hide();
     return false;
}

In the code above the function setFullScreenMode will set the page in full screen mode and hide the siteaction and the full screen button. This code need to be executed after the MDS finishes. I hooked this function inside the jQuery load to the MDS script pipeline asyncDeltaManager.add_endRequest to make sure that the function executed after everything is loaded.

Upload a wsp file to Office 365 (SP 2013) using WebClient

In recent project I need to create a script to apply a design package to site collections in SharePoint Online. The first thing I need to do is to upload the design package (wsp file) to a document library. There is Client API to upload the file to SharePoint but there is size limitation, so I decided to use WebClient  PUT method instead. There are some catches that I found when using this approach:

  • I couldn’t just set the WebClient.Credentials to SharePoint Online Credentials as I would get 403 error. Solution: I need to send the SharePoint security token back as a FedAuth cookie, as a result I need to have a custom WebClient that has Cookie Container
  • I was getting ServerException (Unable to read cabinet info from) when run the Client API DesignPackage.Install on the uploaded wsp file. And I found that the WebClient.UploadFile method somehow didn’t maintain the file format properly. Solution: I need to use the OpenWrite method and upload it in a stream

Below is the working code. First I created a custom web client that accepts Cookie. There is other benefit of using this approach as we have more control on the web request object such as we can increase the timeout as well.

    class SPWebClient : WebClient
    {
        public CookieContainer CookieContainer { get; set; }

        protected override WebRequest GetWebRequest(Uri address)
        {
            HttpWebRequest request = base.GetWebRequest(address) as HttpWebRequest;
            if (request != null)
            {
                request.CookieContainer = CookieContainer;
            }
            return request;
        }
    }

Below is the upload routine. the site Url is the siteUrl in Office 365, the file Url is the document library url such as “SiteAssets/MyDesignPackage.wsp”, local path is the location of the wsp file in the filesystem.

As I mentioned above that I need to have claim base authentication cookie (“FedAuth”) and set its value as the security token found in the SPOIDCRL. And lastly upload the file in a stream (DON’T use UploadFile method!)

   private static void UploadFile(string siteUrl ,string fileUrl, string localPath, SharePointOnlineCredentials credentials)
        {
            var targetSite = new Uri(siteUrl);

            using (var spWebClient = new SPWebClient())
            {
                var authCookie = credentials.GetAuthenticationCookie(targetSite);
                spWebClient.CookieContainer = new CookieContainer();
                spWebClient.CookieContainer.Add(new Cookie("FedAuth",
                          authCookie.Replace("SPOIDCRL=", string.Empty),
                          string.Empty, targetSite.Authority));
                spWebClient.UseDefaultCredentials = false;
                try
                {
                    Stream stream = spWebClient.OpenWrite(targetSite + fileUrl, "PUT");
                    BinaryWriter writer = new BinaryWriter(stream);
                    writer.Write(IO.File.ReadAllBytes(localPath));
                    writer.Close();
                    stream.Close();
                }
                catch (WebException we)
                {
                    Console.WriteLine(we.Message);
                }
                Console.WriteLine("done");
            }
        }

In the next post I will show you how to use the DesignPackage CSOM to install and apply the Design Package.