Jaap Vossers' SharePoint Blog

Just another WordPress.com site

Archive for the ‘jQuery’ Category

Using jQuery to submit forms on remote SharePoint admin pages

with one comment

Imagine you need to develop a piece of functionality to extend SharePoint, but the available APIs do not directly allow you to do this for any of the following reasons:

  1. You are not allowed to deploy any server side code
  2. The server side code you can deploy has limited access to the server object model (e.g. Sandbox Solutions in SharePoint 2010).
  3. The API you need to access is private or internal

Consider the following scenario.

For our SharePoint Online site, we want to implement a Web Part that allows us to save the current site as a WSP in the solution gallery. As it’s SharePoint Online, we can’t deploy Farm Solutions, so we will have to deploy it as a Sandbox Solution. Unfortunately, we have limited access to the Object Model on the server, and there is nothing available in the Client Object Model which we can use to save the current site as a template.

Now, if there is an existing administration page that does what we want to do (in our case /_layouts/savetmpl.aspx does what we want to do), then technically all we need to do is a submit an HTTP POST request to that page with the right HTTP headers and form parameters and the server will happily process the request, as it has no way of telling whether the request was triggered by a user submitting the form, or by something else.

Welcome to the world of stateless protocols.

So we need to find out what the request should look like so that we can use jQuery to build it and issue it as an AJAX request from our own code.

image

Let’s open up Fiddler. With Fiddler open, in the browser we press the button that submits the form on /_layouts/savetmpl.aspx,. After that, we can inspect the form parameters of the HTTP POST request that the browser then makes. We are not really interested in the HTTP headers as the browser will take care of passing any headers related to the current browser session (including the authorization header) to the server when we issue an AJAX request.

image

We have three main categories of form parameters.

The first category is made up of parameters that directly map to user input fields.

  • ctl00$PlaceHolderMain$ctl00$ctl00$TxtSaveAsTemplateName
  • ctl00$PlaceHolderMain$ctl01$ctl00$TxtSaveAsTemplateTitle
  • ctl00$PlaceHolderMain$ctl01$ctl01$TxtSaveAsTemplateDescription
  • ctl00$PlaceHolderMain$ctl03$CbSaveData

The second category consists of a set of hidden fields which are used by ASP.NET & SharePoint to do its postback magic, including validation of the form post.

  • __REQUESTDIGEST
  • __VIEWSTATE
  • __EVENTVALIDATION

The third category is “the rest”. This is stuff we are not really interested in, but we still need to send it to the server.

  • MSOWebPartPage_PostbackSource
  • MSOTlPn_SelectedWpId
  • MSOTlPn_View
  • MSOTlPn_ShowSettings
  • MSOGallery_SelectedLibrary
  • MSOGallery_FilterString
  • MSOTlPn_Button
  • MSOSPWebPartManager_DisplayModeName
  • MSOSPWebPartManager_ExitingDesignMode
  • MSOWebPartPage_Shared
  • MSOLayout_LayoutChanges
  • MSOLayout_InDesignMode
  • MSOSPWebPartManager_OldDisplayModeName
  • MSOSPWebPartManager_StartWebPartEditingName
  • MSOSPWebPartManager_EndWebPartEditing
  • _maintainWorkspaceScrollPosition
  • __spText1
  • __spText2

It’s easy to determine what we want to submit as values for the first category. We either capture these values in our custom UI, or we have some logic in our code that determines these values for us.

The second category is a bit more difficult. Essentially, the server is expecting us to post back these values, which were provided by the server and rendered on the page as hidden input fields at the time of requesting the page which has the form on it. This means we need to make an initial GET request using jQuery so we can extract the values from the form, before we can submit them in our post.

The third category is easy, as we can copy the values from the request we captured with fiddler.

The script

Following the instruction above, we can write a bit of javascript like this to allow us to submit forms on “remote” pages.

function CreateWSP(callback) {

    var sitePrefix = "/";

    if (_spPageContextInfo.siteServerRelativeUrl != "/") {
        sitePrefix = _spPageContextInfo.siteServerRelativeUrl + "/";
    }

    var url = sitePrefix + "_layouts/savetmpl.aspx";

    $.get(url, function (data, textStatus, XMLHttpRequest) {

        var ctx = $(data);

        var rd = ctx.find("[name='__REQUESTDIGEST']").val();
        var vs = ctx.find("[name='__VIEWSTATE']").val();
        var ev = ctx.find("[name='__EVENTVALIDATION']").val();

        var postParams = {
            "MSOWebPartPage_PostbackSource": "",
            "MSOTlPn_SelectedWpId": "",
            "MSOTlPn_View": "0",
            "MSOTlPn_ShowSettings": "False",
            "MSOGallery_SelectedLibrary": "",
            "MSOGallery_FilterString": "",
            "MSOTlPn_Button": "none",
            "MSOSPWebPartManager_DisplayModeName": "Browse",
            "MSOSPWebPartManager_ExitingDesignMode": "false",
            "__EVENTTARGET": "ctl00$PlaceHolderMain$ctl02$RptControls$BtnSaveAsTemplate",
            "__EVENTARGUMENT": "",
            "MSOWebPartPage_Shared": "",
            "MSOLayout_LayoutChanges": "",
            "MSOLayout_InDesignMode": "",
            "MSOSPWebPartManager_OldDisplayModeName": "Browse",
            "MSOSPWebPartManager_StartWebPartEditingName": "false",
            "MSOSPWebPartManager_EndWebPartEditing": "false",
            "_maintainWorkspaceScrollPosition": "0",
            "__REQUESTDIGEST": rd,
            "__VIEWSTATE": vs,
            "__SCROLLPOSITIONX": "0",
            "__SCROLLPOSITIONY": "0",
            "__EVENTVALIDATION": ev,
            "ctl00$PlaceHolderMain$ctl00$ctl00$TxtSaveAsTemplateName": "VossersTeamSite.wsp",
            "ctl00$PlaceHolderMain$ctl01$ctl00$TxtSaveAsTemplateTitle": "Vossers Team Site",
            "ctl00$PlaceHolderMain$ctl01$ctl01$TxtSaveAsTemplateDescription": "Vossers Team Site Template",
            "ctl00$PlaceHolderMain$ctl03$CbSaveData": "on",
            "__spText1": "",
            "__spText2": ""
        };

        var options = {
            url: url,
            type: "POST",
            data: postParams,
            success: function (data, textStatus, XMLHttpRequest) {

                callback();

            }
        };

        $.ajax(options);

    }, "html");
}

Things to consider

When the page you are posting to is modified, for example by a SharePoint update, then it’s possible that your script breaks due to changes in form parameter names. This makes this technique a bit fragile. For this reason I recommend that you only consider using this technique once you have confirmed that it’s not possible to achieve what you want by using public APIs.

Written by jvossers

February 4, 2012 at 3:22 pm

SharePoint InlineSiteSettings 2010 – improved productivity for Administrators and Developers

leave a comment »

After having released SharePoint InlineSiteSettings for SharePoint 2007 a while ago, and having used a little desktop application called Launchy which is used to start desktop applications using just a few keystrokes, I decided to build an enhanced version of InlineSiteSettings, built for SharePoint 2010 with features similar to Launchy’s.

The end result is SharePoint InlineSiteSettings 2010, which can be downloaded from CodePlex at http://sitesettings2010.codeplex.com/

inlinesitesettings2010

The purpose of the solution is to improve productivity for SharePoint 2010 users who regularly access the Site Settings page, i.e. SharePoint Administrators and SharePoint Developers. It allows them to access the Site Settings in a dialog by pressing Ctrl+s, so no need to move your mouse to Site Actions, click it, click Site Settings, and wait for the full page to load.

As we all know, once the Site Settings page has been loaded, it can actually take a few seconds to spot the link you are looking for (as the links are not listed in alphabetical order), so what’s new in this version of SharePoint InlineSiteSettings is that users can start typing the title of the link they whish to navigate to, and with real-time filtering functionality, all links that do not match your filter will disappear from view. In addition to that, as soon as exactly one link is left that matches your filter, it will automatically redirect you to that page, as can be seen in the demo screencast below. As a result, navigating between administrative pages in SharePoint 2010 will be less painful.

SharePoint InlineSiteSettings 2010 is packaged as a Sandbox Solution, and does not depend on any server side code. The good thing about this is that it works on SharePoint Online (Office365).

Download SharePoint InlineSiteSettings 2010 from CodePlex

Written by jvossers

May 8, 2011 at 9:59 pm

Bypass caching with jQuery AJAX GET requests

with one comment

As I seem to use this trick quite often and I keep forgetting the exact details on how to implement it, I thought it would be good to document this.

Using jQuery, I often make ansynchronous GET requests to a custom ASHX handler in SharePoint’s _layouts folder which returns some data that I want to display. This data is always dynamic, but sometimes the browser tries to cache the results from the previous request, so you might not get the response you expected.

To avoid this, simply make the url for eacht request unique by adding a timestamp to it in javascript.

var url = '/_layouts/MyProject/MyHandler.ashx?unique=' + new Date().getTime();

Written by jvossers

January 11, 2011 at 10:41 am

jQuery Developer Frameworks for SharePoint

with 2 comments

If you are into developing SharePoint solutions using jQuery, you should really have a look at the following GREAT CodePlex projects. Both projects have been developed by real experts in the SharePoint & jQuery field 🙂

jPoint – Developed by a team lead by Will Lawrence (@willhlaw)

jPoint is an open source javascript API and script deployment framework for Sharepoint. It leverages the speed and agility of jQuery to manipulate Sharepoint forms and pages, communicate to Sharepoint webservices, and to build jPart plugins.

jQuery Library for SharePoint Web Services – Developed by Marc D Anderson (@sympmarc)

This is a jQuery library which abstracts SharePoint’s Web Services and makes them easier to use. It also includes functions which use the various Web Service operations to provide more useful (and cool) capabilities. It works entirely client side and requires no server install.

Written by jvossers

December 16, 2009 at 12:06 pm

Released: SharePoint 2010 Developer Dashboard Visualizer

with 5 comments

As announced before, I have been working an open source project that visualizes the data in the Developer Dashboard in SharePoint 2010.

The good news is that SharePoint Developer Dashboard Visualizer is now up on CodePlex.

SharePoint 2010 Developer Dashboard Visualizer is a jQuery-based solution that extends the Developer Dashboard by plotting an interactive diagram with data from the Developer Dashboard, giving you an **instant** insight into where the bottlenecks are in your code.

(yes, well spotted… I was stupid enough not to rename my machine before installing SharePoint 2010)

The installer is just a WSP so it’s a quick and easy install!

Finally, a big thank you goes out to Bil Simser for being the first person to post a review for SharePoint Developer Dashboard Visualizer online.

Written by jvossers

December 13, 2009 at 10:12 pm

How to interpret the information in the Developer Dashboard in SharePoint 2010

with 3 comments

When I first had a look at the Developer Dashboard in SharePoint 2010 I was a bit confused. The numbers shown in the nested unordered list on the left, representing load times in milliseconds, didn’t seem to actually cover 100% of the the request that was being handled. Basically it turns out that there are “gaps” that are not monitored, which is exactly why the sum of execution times for a certain set of child nodes in the list often don’t match the execution time of the parent. This is due to the SPMonitoredScope model.

Each node in the list represents a SPMonitoredScope that was created, either in SharePoint OOTB code or in code that you wrote yourself. When a second SPMonitoredScope is created before the first one is disposed, the second one will be treated as a child scope of the first one. In the context of a web request, the top level scope is instantiated in the SPRequestModule. Scopes that you instantiate yourself will most likely become child scopes of this “Request scope”.

Lets look at an example for a custom Visual WebPart that creates it’s own scopes.

   1:  protected void VisualWebPart1_Load(object sender, EventArgs e)
   2:  {
   3:      using (SPMonitoredScope mainScope = new SPMonitoredScope("VisualWebPart1_Load mainScope"))
   4:      {
   5:          Thread.Sleep(5000); // some processing that is not inside a subscope
   6:   
   7:          using (SPMonitoredScope subScope1 = new SPMonitoredScope("VisualWebPart1_Load subScope1"))
   8:          {
   9:              Thread.Sleep(1000);
  10:          }
  11:   
  12:          using (SPMonitoredScope subScope2 = new SPMonitoredScope("VisualWebPart1_Load subScope2"))
  13:          {
  14:              Thread.Sleep(1000);
  15:          }
  16:   
  17:          using (SPMonitoredScope subScope3 = new SPMonitoredScope("VisualWebPart1_Load subScope3"))
  18:          {
  19:              Thread.Sleep(1000);
  20:          }
  21:      }
  22:  }

Now let’s look at the resulting Developer Dashboard output.

scopes

Do you see what I mean?

Now on  a similar note, I have been working on a project that visualizes the data rendered by the Developer Dashboard. It’s just not easy enough to spot “peaks” without it. 

As you might have guessed, it’s a jQuery based solution. I am hoping to put it on CodePlex soon. Here is a sneak peek (click to enlarge):

devdashvis1

Written by jvossers

November 27, 2009 at 4:44 pm

Released: SharePoint LiveListData

with 20 comments

Last week I published my fourth CodePlex project, called SharePoint LiveListData. It is an “assembly-free”  solution which means that it contains no server side code. It is implemented as a jQuery plugin.

So what does it do? It uses AJAX to automatically reload any list-based Web Parts as soon as a change in the underlying list data is detected. You can also have your custom web parts refreshed, as long as they have a web part property that contains the ID of the list they depend on!

I have put online a screencast that demonstrates the the user experience.

Want to know how it works? Allow me to describe using some pseudo code..

  • OnDocumentLoaded
    • Make a single call to WebParts.asmx web service using AJAX to return an xml document with all web parts on the current page
    • Parse returned xml and find all web part nodes that contain a ListID element (which holds the value for the ListID web part property)
    • Create and populate a javascript object that contains a list of all ListIDs that we found in the returned xml, plus a list of all WebPartIDs per ListID, also retrieved from the xml (more or less creating a hashtable with the key being the ListID and the value being an array or WebPartIDs).
    • LOOP with interval = $configured_interval
      • Make a single call to Lists.asmx web service using AJAX to retrieve “LastDeleted” and “Modified” properties for each ListID in the hashtable that was created earlier.
      • For each ListID in hashtable
        • compare values for LastDeleted and Modified with those values retrieved as part of the previous loop iteration for this ListID (unless it’s the first iteration).
        • If a change in one of the two property values has been detected (indicating that someone inserted, updated or deleted an item) mark this ListID as “UpdatePending”, storing it on our javascript object that holds our ListIDs and WebPartIDs.
      • If any of the ListIDs are marked as UpdatePending
        • Make an AJAX request to page that is currently loaded in the browser (allowing us to get a fresh copy of the current page containing the new list data)
        • For each ListID marked as UpdatePending
          • For each WebPartID associated with ListID in our javascript hashtable object thingy
            • Replace div with matching WebPartID attribute in current document with “same” div in AJAX response (which contains the new list data).

This is basically how it works in a nutshell.

For examples on usage, check out the downloads tab on the SharePoint LiveListData CodePlex site, where you can also download the script!

Written by jvossers

November 3, 2009 at 11:40 pm