May 03 2013

Determine if a SharePoint Publishing Page Is in Design Mode (Edit Mode) with Script

Today I was working on some script for the home page of a SharePoint 2013 site which added the jQueryUI accordion behaviour to all of the Web Parts within a Web Part Zone. When I went into edit mode, it was pretty frustrating to have the accorsdions kick in, so I looked around for a way to check to see if a publishing page is in editing mode with script. I’m pretty syure I’ve done this before, but it’s been a while and I couldn’t find anything in my kit.

Somewhat to my surprise, there were a lot of questions about how to do this out there, but not a lot of good answers. Most of them came down to looking for some element that would only be in the page in edit mode and sounded a little kludgy.

However, I found one over at SharePoint Stack Exchange from Andrey Markeev in a thread called How do I know if the page is in Edit Mode from JavaScript? that looks pretty solid to me.

I’m taking the liberty of including the code here, since this is the first place I look for answers!

var inDesignMode = document.forms[MSOWebPartPageFormName].MSOLayout_InDesignMode.value;

if (inDesignMode == "1")
{
    // page is in edit mode
}
else
{
    // page is in browse mode
}

This will refer to value of the following html input control, which is rendering on the page when it is in edit mode:

For wiki pages, you will need the _wikiPageMode parameter:

var wikiInEditMode = document.forms[MSOWebPartPageFormName]._wikiPageMode.value;

if (wikiInEditMode == "Edit")
{
    // wiki page is in edit mode
}
else
{
    // wiki page is not in edit mode
}

Permanent link to this article: http://sympmarc.com/2013/05/03/determine-if-a-sharepoint-publishing-page-is-in-design-mode-edit-mode-with-script/

May 01 2013

Comparing SPServices 2013.01 Calls with Async vs. Promises Methods

SPServices 2013.01 is almost ready for release and I’m hoping that when you see the coolness here that you’ll want to get your hands on the beta to do a little testing with it.

I’ve put together a pretty simple demo page to show how great it can be to use jQuery .Deferred objects (aka promises) to retrieve data with SPServices versus the asynchronous way we’ve tended to use until now. The demo page is running on my old WSS 3.0 site hosted at FPWeb. Unfortunately, I don’t have a public-facing SharePoint 2013 instance anywhere yet.

The idea here is pretty simple. I wanted to keep the complexity of the code pretty low and also to use as much common code as possible between the two methods so that the real apples to oranges comparison is the async method versus the promises method.

I’ve set up three Announcements lists in a single site: Corporate Announcements, Finance Announcements, and HR Announcements. Each list has three announcements in it. I even got to use Bacon Ipsum to fill in some dummy content.

The demo page has two buttons on it: one for async and one for promises. When you push one of the buttons, the script loops through the array containing information about the three lists, retrieves the three items from each of the lists using the chosen method, and displays them on the page. There’s a slightly different version of the code in each of the functions (getRecentAnnouncementsAsync and getRecentAnnouncementsPromises) that run in each case.

The getRecentAnnouncementsAsync function runs the way we’re all used to using SPServices. The async option is set to true and processing of the returned data happens inside the completefunc.

In the promises version, the async option isn’t set, so it has the default of false (we don’t wait for the returned data, but continue processing). The promise returned from each call to GetListItems is put into an array, and the line $.when.apply($, announcementsPromises).done(...) is where the check for all three promises to be complete happens. When that occurs, the data for the three calls is processed.

Here’s the code:

// Show the most recent Announcements from three lists in the current site
var announcementsPerList = 3;
var lists = [
    {name: "Corporate Announcements"},
    {name: "HR Announcements"},
    {name: "Finance Announcements"}
  ];
var camlQuery = "<Query><OrderBy><FieldRef Name='Created' Ascending='FALSE'/></OrderBy></Query>";
var camlViewFields = "<ViewFields>" +
    "<FieldRef Name='ID' />" +
    "<FieldRef Name='Title' />" +
    "<FieldRef Name='Body' />" +
    "<FieldRef Name='Author' />" +
    "<FieldRef Name='Created' />" +
    "<FieldRef Name='FileDirRef' />" +
  "</ViewFields>";
var out;

$(document).ready(function() {

//$("#ctl00_site_share_button").hide();
  $("input[value='async']").click(function() {

    getRecentAnnouncementsAsync();

  });

  $("input[value='promises']").click(function() {

    getRecentAnnouncementsPromises();

  });

});

//++++++++++++++++++++++++++++++++++++

function getRecentAnnouncementsAsync() {

  var recentAnnouncementsContainer = $("#demo-recent-announcements");
  recentAnnouncementsContainer.empty();
  recentAnnouncementsContainer.addClass("demo-loading");

  out = "<table>";
  announcementHeader();

  for(var i=0; i < lists.length; i++) {

    $().SPServices({
      operation: "GetListItems",
      async: true,
      listName: lists[i].name,
      CAMLQuery: camlQuery,
      CAMLViewFields: camlViewFields,
      CAMLRowLimit: announcementsPerList,
      completefunc: function(xData) {

        // List header
        out += "<tr><td class='demo-section-header' colspan='99'>" + lists[i].name + "</td></tr>";

        $(xData.responseXML).SPFilterNode("z:row").each(function(itemNum) {

          processAnnouncement(i, $(this));

        });

      }
    });

  }

  out += "</table>";
  $("#demo-recent-announcements").removeClass("demo-loading");
  recentAnnouncementsContainer.html(out);

}
function getRecentAnnouncementsPromises() {

  var recentAnnouncementsContainer = $("#demo-recent-announcements");
  recentAnnouncementsContainer.empty();
  var announcementsPromises = [];
  recentAnnouncementsContainer.addClass("demo-loading");

  out = "<table>";
  announcementHeader();

  for(var i=0; i < lists.length; i++) {

    announcementsPromises[i] = $().SPServices({
      operation: "GetListItems",
      listName: lists[i].name,
      CAMLQuery: camlQuery,
      CAMLViewFields: camlViewFields,
      CAMLRowLimit: announcementsPerList
    });

  }

  // When all of the promises are fulfilled...
  $.when.apply($, announcementsPromises).done(function() {
    for(var i=0; i < lists.length; i++) {

      // List header
      out += "<tr><td class='demo-section-header' colspan='99'>" + lists[i].name + "</td></tr>";

      $(announcementsPromises[i].responseXML).SPFilterNode("z:row").each(function(itemNum) {

        processAnnouncement(i, $(this));

      });

    }

    out += "</table>";
    $("#demo-recent-announcements").removeClass("demo-loading");
    recentAnnouncementsContainer.html(out);

  });

}

function getNow() {

  return new Date();

}

function announcementHeader() {

  out += "<tr class='ms-WPHeader'><td colspan='99'><h3 class='ms-standardheader ms-WPTitle'>Recent Announcements as of " + getNow() + "</h3></td></tr>";
  out += "<tr>" +
      "<th class='ms-vh2'>Title</th>" +
      "<th class='ms-vh2'>Body</th>" +
      "<th class='ms-vh2'>Created By</th>" +
      "<th class='ms-vh2'>Created</th>" +
    "</tr>";

}

function processAnnouncement(i, item) {

  out += "<tr>";

  // Title as a link to the announcement
  var thisLink = item.attr("ows_FileDirRef").split(";#");
  out += "<td class='ms-vb demo-note-details' style='width:40%;'>" +
      "<a href='/" + thisLink[1] + "/DispForm.aspx?ID=" + thisLink[0] + "&Source=" + location.href + "' data-announcement-id='" + item.attr("ows_ID") +
        "' data-list='" + lists[i].name + "' >" +
        item.attr("ows_Title") +
      "</a>" +
    "</td>";

  // Body
  var thisBody = item.attr("ows_Body");
  out += "<td class='ms-vb'>" + ((typeof thisBody !== "undefined") ? thisBody : "NA") + "</td>";

  // Author as a link to the User Profile
  var thisAuthor = item.attr("ows_Author").split(";#");
  out += "<td class='ms-vb' style='width:15%;'>" +
      "<a href='/_layouts/userdisp.aspx?ID=" + thisAuthor[0] + "' onclick='GoToLink(this);return false;'>" + thisAuthor[1] + "</a>" +
    "</td>";

  // Created date/time
  out += "<td class='ms-vb' style='width:15%;'>" + item.attr("ows_Created") + "</td>";

  out += "</tr>";

}

Note that I’m using the same version of SPServices here. SPServices 2013.01 can be used as you’re used to using it and everything will work as you are used to. If you are making multiple calls and the promises method would make more sense (mainly in terms of efficiency), then you can take advantage of it.

There are two big benefits of using the promises method:

  • If there are multiple calls to the Web Services that can logically happen concurrently (there’s less benefit if there is only one call), the promises method allows that to happen.
  • In the promises method, the browser doesn’t get locked up like it does with the async method. Setting async to true means that the browser is going to wait for the results to come back from the call before it will allow anything else to happen. With promises, the processing continues even when the results aren’t available. (This can take some getting used to, and I’ll undoubtedly do more posts about it.)

I’ve tested the code in SharePoint 2013 on Office365 and WSS 3.0 at FPWeb, which are about the most opposite ends of the spectrum that we can try these days. The code that I tested is *exactly* the same in the two environments. I simply copied and pasted the file from SharePoint 2013 where I started into the WSS 3.0 environment. How’s that for consistency, even on a downgrade? Oh, if Microsoft’s code only did that!

Using Firebug, I’ve captured information from the two methods on the Net tab for the XHR traffic.

Here are the results in SharePoint 2013:

Async

image

Promises

image

As you can see the total elapsed time decreased from about 503ms to 107ms. These results are fairly consistent. I haven’t tried to build any fancy instrumentation around it, but if I click the buttons repeatedly, I get consistent results in both cases.

Here are the results from WSS 3.0:

Asynch

image

Promises

image

Here, the total elapsed time decreased from about 409ms to 130ms.

In both versions of SharePoint, you can quite obviously see the difference. With the async method, the three calls happen in order, whereas with the promises method, they happen pretty much concurrently. (Even with promises, there’s a small lag due to the processing to set up the calls.)

But don’t take my word for it. go and grab your own copy of SPServices 2013.01 and try it yourself.

Permanent link to this article: http://sympmarc.com/2013/05/01/comparing-spservices-2013-01-calls-with-async-vs-promises-methods/

Apr 27 2013

SharePoint Saturday Boston 2013 Wrap Up

Thanks to all who came to my session “Creating a Great User Experience in SharePoint” today at SharePoint Saturday Boston 2013. As promised, I’ve posted the slides to SlideShare. You can either view them on SlideShare or below.

As always, I learned a lot from the conversations and other sessions. It’s great to have the chance to talk to people about what they are doing with SharePoint and especially SPServices. (The new SPServices 2013.01 is ready for release! Just a little tidying up and some doc writing.)

A big THANK YOU goes out to Talbott Crowell (@talbott), Geoff Varosky (@gvaro), Chris Bortlik (@cbortlik), and especially Pradeepa “Peeps” Siva (@PipsTips) who puts up with them and the rest of us SharePoint freaks.

Permanent link to this article: http://sympmarc.com/2013/04/27/sharepoint-saturday-boston-2013-wrap-up/

Apr 16 2013

SharePoint Designer 2013 Crashing on Open Site: The Fix

The Problem

My Office365 tenant has become half-upgraded from SharePoint 2010 to SharePoint 2013. (If you want to read more of my whinging about this, checkout this thread on SPYam.)

This leaves me in the unenviable position of having to use SharePoint Designer 2013 (SPD2013) with my SharePoint 2010 Office 365 tenant. Unenviable because, as anyone who follows me even occasionally knows, the Design and Split Views are not available in SharePoint Designer 2013. That thread that I started on TechNet has over 28,000 views, so I don’t think that I’m the only one upset by this.

When I installed SPD2013 on my laptop, all went well. However, every time I tried to use the Open Site dialog, it would crash. SharePoint Designer 2010 (SPD2010) was still working fine when I accessed other 2010-based installations, but not SPD2013.

I found a fix that worked for me in the Technet forums. You may or may not want to trawl through the thread, as it is quite long. Instead, here’s the Cliff Notes version of what worked for me.

Sungmin Kim from Microsoft offered up this check.

You can repair your SPD 2010 to restore the regkey for SPD2010.

The issue might happen in case the ClientGUID of the Open Site dialog in SPD14 is the same as the one of the open site dialog in SPD 15 in a certain Side by Side environment.

(this repro’s only in a specific environment, but I couldn’t find the enviroment yet and when the GUIDs could be the same)

so I have couple of questions. Sorry to bother you, :(

1. Could you please check if ClientGUID value under HKEY_CURRENT_USER\Software\Microsoft\Office\14.0\Common\Open Find\Microsoft SharePoint Designer\Settings\Open Site is the same as the ClientGUID value under HKEY_CURRENT_USER\Software\Microsoft\Office\15.0\Common\Open Find\Microsoft SharePoint Designer\Settings\Open Site?

2. If the values are the same, could you please check if the crash still happens after removing both registry keys?

3. Have you ever installed any other version of SPD15 on your machine? (e.g. beta version) or any other version of SPD14?

4. if the issue still happens at #2, how about removing the registry key HKCU\Software\Microsoft\Windows\CurrentVersion\Explorer\ComDLg32\LastVisitedPidlMRU ?

Points 1 and 2 did the trick for me. Apparently both SPD2010 and SPD2013 had the same GUID for the ClientGUID value in the registry. I had not installed any betas of SPD2013 on my laptop because I was concerned about exactly this sort of incompatibility. (I’d limited my use of SPD2013 to launching it inside virtual machines.)

The Fix

If you have this problem and want to fix it, here are the steps.

Open the Registry Editor. You can do this by going to the Start menu (I’m still a Windows 7 stalwart, so I can’t vouch for how this might work on Windows 8), choosing “Run”, and typing “regedit” in the Open: box.

Look for the keys:

HKEY_CURRENT_USER\Software\Microsoft\Office\14.0\Common\Open Find\Microsoft SharePoint Designer\Settings\Open Site

and

HKEY_CURRENT_USER\Software\Microsoft\Office\15.0\Common\Open Find\Microsoft SharePoint Designer\Settings\Open Site

In my case, they were identical, as shown below.

SharePoint Designer 2010 (14.0)

image

SharePoint Designer 2013 (15.0)

image

Delete both of the ClientGUID keys. You can do this by highlighting the key and hitting the Delete key or right clicking and choosing Delete.

Once I had deleted these two registry keys, I was able to open sites in both versions of SharePoint Designer with no problems.

Unfortunately, the two versions of SharePoint Designer seem to use the same recent sites list, so I see the same Recent Sites in both versions. This is going to make it confusing when I am trying to figure out which site to open. Now I’m a three SharePoint Designer version guy, as I’m still using SPD2007 and SPD2010 for client work in addition to SPD2013. Yeesh.

Permanent link to this article: http://sympmarc.com/2013/04/16/sharepoint-designer-2013-crashing-on-open-site-the-fix/

Apr 15 2013

SPServices Stories #13: Durandal SP3: Developing SharePoint SPAs Made Easy

This entry is part 13 of 13 in the series SPServices Stories

Introduction

Rainer Wittman (@RainerAtSpirit) and I have been emailing back and forth for a few weeks now. He’s been trying out the new alpha of SPServices 2013.01 which includes jQuery promises aka Deferred objects capabilities (soon to be a real release, I promise!) with the Durandal JavaScript framework. Durandal is a framework for building SPAs, or Single Page Applications.

This is something that SharePoint 2013 does to some degree with the Minimal Download Strategy (MDS). If you’re interested in how MDS works, here are some posts that go into more detail about it:

Those of you who are purists will tell me that I’m comparing apples and oranges, and that’s sort of true. However, the goals are similar: send as little of the page transitions down the wire as possible to make those transitions as fluid and responsive as possible. We see this sort of approach more and more, especially in mobile interfaces.

I’ve done SPA-like things even with SharePoint 2007 using AJAX. By maintaining the overall chrome of the page (top nav, Quick Launch, footer) as a constant, we can do something as simple as AJAXing in a new copy of the same page, parsing out the main panel, and replacing it in the user’s current copy of the page in the DOM. You also see this in SharePoint 2010 with the asynchronous refresh capability available with some Web Parts (See: Asynchronous
Update in SharePoint 2010
from @wonderlaura).

If you haven’t heard of Durandal (I hadn’t), here’s some information swiped from the Durandal home page:

Comfortable

We didn’t try to re-invent the wheel. Durandal is built on libs you know and love like jQuery, Knockout and RequireJS. There’s little to learn and building apps feels comfortable and familiar. Dive in and enjoy.

Feature-rich

MVC? MVP? MVVM? Yes. Messaging, navigation, modals? Check. Durandal has the features you need to build whatever apps you can imagine; the apps of today and of tomorrow. Let your creativity soar.

Versatile

Building an Android phone app? An enterprise LOB targeted at Windows? A web gaming platform? No matter how large or small the app, it’s effortless with Durandal….and we give you the tools to develop on any platform, for any platform.

I expect we’ll hear more from Rainer about this cool way of building SharePoint interfaces. As you read through his post below, you’ll probably be very impressed to see that his approach works for SharePoint 2007, 2010, or 2013. If you’re still on 2007 and woulds like to make your installation fell a heck of a lot more “modern”, this is an approach that has legs going forward. You’ll also see some links in his post to live, working demo pages so that you can get a feel for what he is driving at.

This article was originally posted on Rainer’s blog at Durandal SP3: Developing SharePoint SPAs made easy.

Durandal SP3: Developing SharePoint SPAs Made Easy

Hi there,

In the last post I introduced you to Durandal a SPA Framework, which can be used to create SPAs on top of the SharePoint infrastructure. This time we’re going to leverage Marc Anderson’s SPServices as a data service for our SPA.

The obvious advantage is that web services are around for a long time, so one SPA (same code base) runs in SharePoint (2003), 2007, 2010 and 2013.

The obvious disadvantage is that web services are deprecated in 2013, so they might go away with the next major release. If you are already running on 2010/2013 and don’t have to support older browser versions you might want looking into using REST services with JayData or Breeze instead… but that’s worth another story.

Seeing is believing so here a couple of screen shots using IE versions that roughly matches the SP release time.

SharePoint 2013 | IE 10: 2013-04-08-SP2013Demo

SharePoint 2010 | IE 8:

2013-04-08-SP2010Demo

SharePoint 2007 | IE 7:

In SP2007 you’ll notice some issues with the CSS that is used in the SPA otherwise it’s fully functional. That is less an issue with IE7, but more with SP2007 that is running pages in Quirks mode. A quick workaround would be to apply a DOCTYPE to the pages that host your SPA.

2013-04-08-SP2007Demo

SharePoint 2003 | IE 6:

Sorry, I’m out of historic SharePoint VMs. Please give me a shot if somebody has still access to a SP2003 environment. I’d love to add the missing screen shot.

Now, after hopefully getting you excited, here’s the bad news. The demo is using the alpha release 2013.01ALPHA5 of SPServices, so I won’t make the demo code available through Github as usual. I’ll update this post once the next official version of SPServices has been released and tested with Durandal SP3.

The good news is that there are two public available pages that allows you to go hands-on. Both are best viewed with your favorite console open.

  1. development version:
  2. optimized build:

Without going into the details let see what the Promises demo app is doing when you activate the list route (/#lists).

  1. Retrieve information about the lists in the current site via SPServices GetListCollection method (with caching)
  2. Retrieve detail information about the selected list via SPServices GetList method and build a mapping that can be used in SPServices SPXmlToJson method (with caching)
  3. Retrieve item information via SPServices GetListItems (NO caching)

Update 2013/04/11: The life demo was updated based on some feedback I got. The list overview now produces a configurable row view of lists with meta information like ItemCount and Last Modified. Step 2 and 3 are performed once you select a list.

By opening up the optimized build and filtering the network tab for XHR you can see the three POST requests to lists.asmx nicely lined up. Once you start selecting other lists, you’ll noticed that the number of XHR requests decrease as more and more cached information becomes available.

2013-04-08-OptimizedBuild

The development version on the other side shows far more details via the console. That allows you to get familiar with Durandal’s application life cycle and to inspect the Json result of some spdata methods.

2013-04-08-Development

After reading so far and hopefully seen the Promises demo in action by yourself, I hope that you share my excitement of the upcoming promise support in SPServices. Once it’s part of an official release SPServices will become a perfect fit for Durandal’s life cycle methods.

Permanent link to this article: http://sympmarc.com/2013/04/15/spservices-stories-13-durandal-sp3-developing-sharepoint-spas-made-easy/

Page 2 of 16112345...102030...Last »
%d bloggers like this: