SPServices Stories #12 – SharePoint and jQuery SPServices in Education: A Case Study

Introduction

Ben Tedder (@bentedder) has long been a fan of SPServices and his writing about it is great, to boot. I liked this post back when Ben first put it up on his blog because it really does tell a story, and SPServices plays a significant role in it.

Ben has built quite a few real-world solutions using SPServices that transcend what SharePoint can do. By using SharePoint as the back end data repository, Ben has managed to create solutions that provide a great user experience and are far more efficient than SharePoint can be when building through the UI. He does this without deploying any server-side code, just as I always aspire to do. Great solutions with minimal footprints.

Thanks to Ben for letting me republish this post from his blog.

SharePoint and jQuery SPServices in Education: A Case Study

24 Sep 2012

bentedder-profile

This is a morphed, updated, renewed version of the SharePoint Scheduling Assistant. I’m not releasing this version quite yet, but this is a brief case study on how it’s working at a specific school.

Business Needs

The International School of Beijing needed a way for Elementary School parents to book time slots with teachers during bi-annual parent-teacher conferences.

The requirements:

  • Easy to use (training is impossible).
  • Integrate into the current intranet portal.
  • Sync with the database to omit any kind of manual setup for secretaries.
  • Deny parents the ability to book more than one slot with the same teacher.
  • Allow parents to book the same slot for two different teachers (in case mother and father come in and meet with 1 teacher each to save time)
  • If two or more parents are online at the same time, correctly queue the submissions so a double booking does not occur.
  • Allow teachers to pre-block out slots where parents cannot book times.
  • Allow teachers the ability to see their entire schedule, including which student is coming in during which time slot.

Solution (SharePoint, jQuery, and SPServices)

A SharePoint solution was built with jQuery to meet the requirements of the Elementary School. Let’s break down how the solution was created:

Part 1 – SharePoint

Within SharePoint three lists were created:

  • Bookings (Each reservation had its own row in this list that stored the details of who booked it, for which teacher, etc.)
  • Time Slots (A pre-determined list of time slots…in this case a list item was created for each 20 minute time slot from 12-6pm on Thursday and Friday Oct 18 and 19).
  • People (An external content type that pulled records from the database for each student, each of their parents, and each of their teacher names)

One of the trickier parts of this solution was grabbing the external content from the database in a usable way. Once it was in, we were able to work with the data. However, this list has 10,000+ items, so dealing with larger data like this was quite challenging. Enter jQuery.

Part 2 – jQuery and SPServices

The bulk of this solution was created with the jQuery and jQuery SPServices Libraries. Using jQuery, we stepped through the process like this:

  1. Get the details of the logged in user (parent) using SPServices
  2. Hit the SharePoint external data list once, filter it by Parent (matching to the Parent login ID), and store it in a javascript object for later use. This was the biggest strain on the system. We minimized the data call to only one time, but even still, pulling a list of 10,000 records even once isn’t super quick.
  3. Get all the children of the logged in parent, push them to a drop-down menu
  4. Get all the teachers of the selected child from #3, push them to another drop-down menu
  5. Get all time slots from the Time Slots list, push to a third drop-down menu
  6. Retroactively disable all time slot options that have already been booked (by searching through the Bookings list for records that match the time slot and the selected teacher)

Once the data was present, the parent could interact with it in two ways, book, and delete.

To book a time slot, the selected child, selected teacher, and selected time slot (along with a comments area) was submitted and saved to the list. To delete a time slot, a delete button is appended to each reservation in the on-screen schedule with the ID of the reservation as the ID of the link element.

The data from the Bookings list is checked once during the time slot selection process, and again during the form submit process to make sure no double bookings have occurred.

Benefits

This solution enables, for the first time at this school, parents to go online and manage their entire Parent-Teacher Conference schedule. Also, as an added bonus, if a mother and father both login, they can see the complete schedule for their child, even if only one of the parents made the bookings.

Once a parent books a time slot, they receive an email containing the details of their reservation.

An additional feature of this solution was that it was duplicated and tweaked for teachers to use a similar interface to pre-block out time slots where they did not want parents to come (ie, lunch, coffee break, going home). In that scenario the “one-block” restriction was removed for teachers, allowing them to customize when parents would be given the option to come in.

The SharePoint Social vs. Yammer Battle – Do We Care?

I’m driven to write this post after reading one by  over the weekend called Gartner: Yammer or SharePoint? The choice is still unclear.

The choice indeed may still seem unclear, but I think that the statement addresses the wrong questions.

In my opinion (I’m the only one here – you talkin’ to me?), we should stop talking about the “social” thing as a thing. Christian Buckley (@buckleyplanet) beat me to the punch in his comment on the post:

Part of the problem here is that we are still dealing with a serious learning curve on what social is, exactly, and how it fits into an organization’s culture and business needs. Microsoft needs to both education and evangelize a vision+roadmap that has not yet been articulated. That’s a tough row to hoe.

Rather than saying we should use SharePoint or Yammer for “social”, we should instead be talking about the specific things that we want people in a given population to be doing (or at least capable of doing – getting them to do it is a different challenge).

Once we understand what that might look like – and the goals will vary greatly by organization – we can start to make intelligent decisions about the right technologies for that particular case. Saying we need “social” means basically nothing. Or anything. Or something in between.

The slide that James showed from the Gartner webinar which prompted *his* post (and no, I did not see the webinar) starts to get at that set of questions, but I would say that it is still from the reverse angle. It’s useful, but it isn’t the point.

workloads-yammer-vs-sp-from-gartner

This sort of tool-driven analysis almost always leads to disappointment in my experience. It’s an easy way out for those who don’t want to do the harder work of understanding what the organization actually needs – and maybe even wants – by saying that this tool or that tool is the better one without clearly understanding the underlying problems in the first place.

Technologies can only support the kind of things that people are lumping under the social sobriquet to a certain degree. The concept of being social covers many things, but note that none of them mention SharePoint or Yammer:

so·cial [soh-shuhl] adjective (from Dictionary.com)
1. pertaining to, devoted to, or characterized by friendly companionship or relations: a social club.
2. seeking or enjoying the companionship of others; friendly; sociable; gregarious.
3. of, pertaining to, connected with, or suited to polite or fashionable society: a social event.
4. living or disposed to live in companionship with others or in a community, rather than in isolation: People are social beings.
5. of or pertaining to human society, especially as a body divided into classes according to status: social rank

I’ve already stopped saying “social” as much as I can – which isn’t easy – opting instead to push people to tell me what they want to accomplish. It makes most of them uncomfortable (or they say “You know, *social*), but in the long run these artificial packaging exercises are the wrong way to go.

Decide what you want to do, then decide which tool is the best match to solve that set of problems.

MetaVis SharePoint MVP Webinars Series – Creating a Great User Experience in SharePoint

Dave Coleman (@davecoleman146davecoleman146) and I had a grand time – Dave and I always seem to have a grand time – with the webinar we did yesterday. It was part of the MetaVis SharePoint MVP Webinars Series and I presented Creating a Great User Experience in SharePoint. It was somewhat a reprise of my SPTechCon session from San Francisco a few weeks ago, but with some tweaks and additions based on the feedback I got afterward. (One of the benefits of doing a session multiple times is that I get to refine it as I go.)

Thanks go out to Dave and the MetaVis team for giving me this opportunity to present.

My slides are available on SlideShare.

And here’s the video:

SPServices Stories #11 – Using SPServices and jQuery to Perform a Redirect from a SharePoint List NewForm to EditForm

Introduction

I ran across this SPServices Story in a post on the blog at CTS. The author of the post, Matt Ingle, is a Senior Consultant at CTS in Birmingham, AL. According to Matt, he is a team lead for a group called the SharePoint Factory. The SharePoint Factory team roles correspond to the various areas of the SharePoint family of products. This role-based approach allows for technical depth and specialization within the SharePoint functional areas.

SPServices has a function called SPRedirectWithID, but it’s problematic in SharePoint 2010 due to the dialogs that SharePoint uses to show the list forms. You can ensure that the function works just fine by turning off the dialogs, but that’s not always desirable. I’d turn them all off if I had my druthers because most list forms require more screen real estate than the dialogs provide without a lot of scrolling. They also don’t obviate the need for a ca-chunk postback when you save the item.

Given this state of things, Matt came up with a way to accomplish a similar thing in a different way. Here’s Matt’s take on the task. It’s a nice way to go if your information architecture is very clear and you know that your forms won’t change much, if at all, since Matt is bypassing the simple NewForm we get for “free” from SharePoint. On the other hand, this type of approach may become more common as we move forward with SharePoint and HTML5 compatibility.

Using SPServices and jQuery to Perform a Redirect from a SharePoint List NewForm to EditForm

By Matt IngleMatt Ingle

Problem: In SP 2010, you have a parent list and multiple child lists connected through Lookup columns. You have created the custom Display and Edit forms for the parent list containing XsltListView web parts for the child lists filtered through query string view parameters. Refer to this article for more information on this solution.

Now you need a way to redirect the user from the NewForm to the EditForm after saving the parent list item while passing the newly created item ID as a query string parameter. The problem is there is no way to do this out-of-the-box (OOB).

Solution: You can use jQuery and the SPServices library from CodePlex to utilize SharePoint’s Web Services. The two operations I will use in the following example are GetUserInfo and UpdateListItems.

Note: Be sure to read the IMPORTANT NOTES on the SPServices Home page about supported versions. This example will use the (“[nodeName='z:row']“) syntax which no longer works with jQuery 1.7. I will be using jQuery 1.6.2 and SPServices 0.6.2 in my example. However, if you want to use 1.7, an alternative solution to using this syntax can be found here by Steve Workman. [ed: Use the SPFilterNode function, which will work with any version of jQuery: .SPFilterNode("z:row") and ensures cross-browser compatibility.]

By using the SPServices operation to create the new list item you will be bypassing the OOB Save process for the SharePoint list form. This means that you will lose the validation on the form and will need to create your own validation logic using jQuery. In the following example I will be implementing the required field validation for my list fields.

Example: At this point you should already have a custom NewForm for your parent list.

Below each field to be displayed on the form, add some text wrapped in a <span> tag with unique ids that will be used to display our custom validation message. I worded mine the same as the text displayed by SharePoint. Notice my id for the <span> tag below is ‘valBU’. We will use jQuery later to select this element by the id.

clip_image0024

Additionally, we will need to add a custom button to our form in place of the OOB Save button. This will allow us to attach our custom code to the Save button’s click event.

clip_image004

Next, add a Content Editor WebPart (CEWP) directly below the DataFormWebPart. This will hold our jQuery/SPServices script.

In the CEWP, add the script references to the jQuery and SPServices libraries. I uploaded mine in a new ‘Scripts’ folder stored in the ‘Style Library’ folder so that it is accessible to other pages in the site as needed.

To begin the script, add code to hide the text containing our custom validation messages. Place this code in the $(document).ready function. Next, add a line to attach the method CreateNewItem to the Save button’s click event.

clip_image006

Next, we can implement our custom validation logic. The following method will be called in our CreateNewItem method to validate our form before creating the new item. It starts by using jQuery selectors to obtain the values of the list fields on the form. We can use the ‘title’ attribute for the selectors which contains the name of the list field. In my example, I have 2 drop-down list boxes so I am looking for select elements. For a normal text field you would look for input elements.

For a PeoplePicker, the selector used is a little different. There are different ways to obtain this value, but for our purposes (looking for a single PeoplePicker on the page) you can just look for a textarea element with the title ‘People Picker’. If you have multiple PeoplePickers on the form then you would need to research a way to be more selective. [ed: You can use the SPFindPeoplePicker function in SPServices for this.]

When you have an empty PeoplePicker value you will get ’&#160;’ which is the HTML code for a non-breaking space. Simply check for this value versus an empty string as done for the other fields.

This method counts the number of empty fields and toggles display of the custom validation messages. If there are no empty required fields then it returns true, false otherwise.

clip_image008

Now we can implement the CreateNewItem method. First, use jQuery to select the form fields and obtain the values.

Again, we need to do something different for the PeoplePicker. The value of the PeoplePicker contains a lot of stuff we don’t really need so we have to parse through it to find the user login name.

With this value stored in the ‘buFinContollerPerson’ variable, we will supply it to the ‘userLoginName’ parameter for the GetUserInfo operation. This will be a value like ‘EXT\mingle’.

We are calling the GetUserInfo operation in order to get the correct format needed to save the PeoplePicker value to the list. This format is ’37;#Matt Ingle’ (<UserID>;#<UserName>).

clip_image010

To complete the CreateNewItem method we will call the UpdateListItems method. To specify the creation of a new list item you need to specify “New” for the batchCmd parameter. In addition, supply the list display name (one shown in UI) for the listName parameter. The values to be submitted for the new list item are specified as value pairs in the valuepairs parameter.

Note:We are supplying the fullUserName obtained from the GetUserInfo operation as the value for the PeoplePicker field BUFinContollerPerson.

Once the operation has completed we will parse the XML response to find the newly created item ID. This is where we use the (“[nodeName='z:row']“) syntax. This value is supplied for the ID query string parameter to redirect the user to the EditForm.

Also notice the <div> tag below the <script> tag. This is where you can specify the location of the debug output for the SPServices operations. Simply uncomment the calls to SPDebugXMLHttpResult to see the operation results displayed. Be sure to comment out the redirect though when debugging, otherwise you will not stay on the page to see the results. :-)

clip_image012

SPTechCon Social Demo

[important]

Mark Miller (@EUSP) and I did a webinar on Friday, March 15, 2013 at  to show the demo again and take questions about how we built it. If you’d like to look at the demo yourself, check out the publicly available page on NothingButSharePoint.com. The video is embedded below.

[/important]

It’s not every day that I get to create something in SharePoint with a Magic button.

Magic Button

I few weeks ago, Mark Miller pinged me asking if I’d be interested in helping him with a demo for his keynote at SPTechCon. When Mark asks, I tend to ask “how high” simply because it’s usually something fun. Sometimes, it’s even useful.

The basic idea was to show a social dashboard in SharePoint without letting on that we were using SharePoint. As you might imagine, none of this went along as linearly as I’m going to describe it. We tried various different things, added and removed columns, and widgets, etc. What I’ll describe is the end result.

First, I knew I wanted to use jQuery, jQueryUI, and SPServices, so I took a copy of default.aspx in a basic Team Site and added the following references. (Yes, I prefer the old Web Part Page over the Wiki pages. It’s much easier to work with. The Wiki pages tend to vomit markup all over what I do.)

<link href="Scripts/social_home_page.css" rel="stylesheet" type="text/css" />
<!-- Reference the jQueryUI theme's stylesheet on the Google CDN. Here we're using the "Start" theme -->
<link href="/ajax/libs/jqueryui/1.10.0/themes/start/jquery-ui.css" rel="stylesheet" type="text/css" />
<!-- Reference jQuery on the Google CDN -->
<script type="text/javascript" src="/ajax/libs/jquery/1.8.3/jquery.min.js"></script>
<!-- Reference jQueryUI on the Google CDN -- >
<script type="text/javascript" src="/ajax/libs/jqueryui/1.10.0/jquery-ui.min.js"></script>
<!-- Reference SPServices on cdnjs (Cloudflare) -->
<script type="text/javascript" src="/ajax/libs/jquery.SPServices/0.7.2/jquery.SPServices-0.7.2.min.js"></script>
<!--<script type="text/javascript" src="http://cdn.dev.skype.com/uri/skype-uri.js"></script>-->
<script type="text/javascript" src="Scripts/social_home_page.js"></script>

Next, I altered the markup for the page in SharePoint Designer. This was a demo, so there was zero concern about repeatability, of course. It’s nice to have that sort of freedom once in a while. By default, the page has a table with two columns set to 70% (left) and 30% (right) width. I simply changed that markup to have four columns, each with 25% width. In each of the two new table columns, I added a Web Part Zone. I wanted to drop as much of the social stuff as I could into the page using Content Editor Web Parts so that I could explain it more easily, like in this blog post. In edit mode, the page looked something like this: 3-11-2013 09-52-09 Next I added some CSS to the social_home_page.css file:

#s4-ribbonrow {
  display:none;
}
.s4-titlerowhidetitle {
  display:none;
}
#s4-leftpanel {
  display:none;
}
#MSO_ContentTable {
  margin-left:0;
}
#MSO_ContentTable table td {
  padding:3px;
}

This simple CSS removed all of the chrome we normally see on the page. In other words, we’ve removed the SharePoint from SharePoint to a large degree. The ribbon, title area, and Quick Launch are all totally hidden. (No screen shot for this – you wouldn’t see anything!) At this point, I had a page that looked like a big white nothing in the browser. Time to add the fun stuff. In Twitter, you can create widgets that display tweets from Twitter much like you can create different streams in HootSuite or TweetDeck. You can find this capability in Settings: 3-11-2013 09-58-00 I created three different widgets:

  • search stream for “EUSP”
  • search stream for “SPTechCon”, and
  • search stream for “SharePoint”

There are a few settings which give you basic control over the look and feel. If we were implementing this “for real”, it would probably make sense to make calls against the Twitter API and get the raw data so that we would have full control over the markup and visuals.3-11-2013 10-05-29 When you create the widget, you get a little snippet of markup and script which you can embed in a Web page. Those snippets are very simple. Here’s what the snippet for EUSP looks like:

<a class="twitter-timeline" href="https://twitter.com/search?q=EUSP" data-widget-id="306449761781817344"></a>
<script>!function(d,s,id){var js,fjs=d.getElementsByTagName(s)[0];if(!d.getElementById(id)){js=d.createElement(s);js.id=id;js.src="//platform.twitter.com/widgets.js";fjs.parentNode.insertBefore(js,fjs);}}(document,"script","twitter-wjs");</script>

I put each snippet into a TXT file so that I could reference them in CEWPs. For the EUSP stream, I have a TXT file called twitter_search_eusp.txt in a Document library, and I just point to that file in the CEWP’s Content Link. This gets the three Twitter streams into the page:

3-11-2013 10-25-53

We also wanted to show something from Yammer, since it plays so importantly into Microsoft’s social story. While there are Yammer Web Parts available, I decided to go the widget route here as well. If you look under Apps in the Yammer Web interface, you’ll find Yammer Embed, which eventually takes you to the Yammer Embed page. There, you’ll find a PDF document that explains how to embed a Yammer feed. (Note to the Yammer folks: This isn’t a very clear process. Opportunity for improvement.)

Here’s what I ended up with for the SPYam feed. Note that I created my own id for the container so that it would fit into my page logic easily.

<script data-app-id="hyB2pTvrL36Y50py8EWj6A" src="https://assets.yammer.com/platform/yam.js"></script>
<script>
yam.connect.embedFeed({
  container: '#yammer-spyam-embedded-feed',
  network: 'spyam' // update with your own
});
</script>
<div id="yammer-spyam-embedded-feed"></div>

For some reason, the Yammer authentication mechanism simply won’t work in my page in Internet Explorer 9, so I switched to Firefox at this point, where I had no problems. (Another place for improvement, Yammer folks. However, it may well be that my IE9 is just sick.)

3-11-2013 10-43-14

Now we have all four streams we want in the page, at least in Firefox, for me.

I had seen some Twitter traffic about Dan McPherson’s lastest entries in the SharePoint Games under the Leap moniker. There are two offerings right now: LeapBackup and LeapMessages. Mark and I thought it would be cool if we could use LeapMessages to send a text message with the contents of a Tweet. I can imagine several use cases for this. Perhaps you work at Burger King, your Twitter account is hacked, and you need to notify the execs…

LeapMessages is really simple to implement. You just sign up on the Leap site, give the site URL and your Office365 credentials (it only works on Office365 right now), and Leap creates a list in your site called LeapMessages. If you add an item to that list, the LeapMessages engine grabs it (it polls every 30 seconds) and sends it out as a text from their gateway. Easy-peasy.

To implement this, I pulled a demo cheat. Since it takes a little time to load up the three Twitter streams and the Yammer stream, I set it up so that when I hovered over the Magic button (see below for more info on the button), this script would run, adding an SMS link at the bottom of each tweet in the three streams. I just had to wait until the three Twitter streams were loaded before I did the hover trick.

$("div.showSharePoint").hover(function () {

  if (!loadedSMS) {

    loadedSMS = true;

    $("iframe[id^='twitter-widget-']").contents().find("ul.tweet-actions").prepend("<ul><li><a class="SMS-send">SMS</a></li></ul>");
    $("iframe[id^='twitter-widget-']").contents().find(".SMS-send").click(function (e) {

      e.preventDefault();
      var thisTweet = $(this).closest("div.footer").closest("li");
      var thisTweetText = thisTweet.find("div.e-entry-content").text().trim();
      var thisTweetFullName = thisTweet.find("div.header span.full-name").text().trim();
      var thisTweetNickName = thisTweet.find("div.header span.p-nickname").text().trim();
      messageText.val("Interesting tweet from " + thisTweetFullName + " (" + thisTweetNickName + ") " + thisTweetText);
      countChars();

      $("#dialog").dialog("open");

    });
  }

}, function () {
  // Nothing to do
});

I added this markup at the bottom of the page for the dialog that would pop up when I clicked the SMS links.

<div id="dialog" title="Send SMS Message">
  <p class="validateTips">All fields are required.</p>
  <head>
    <meta name="WebPartPageExpansion" content="full" />
  </head>
  <form>
    <fieldset>
    <label for="phoneNumber">Phone Number</label>+1
    <input type="text" name="phoneNumber" id="phoneNumber"
    class="text ui-widget-content ui-corner-all" />
    <br />
    <label for="messageText">Message</label>
    <textarea rows="5" cols="40" name="messageText"
    id="messageText" value=""
    class="text ui-widget-content ui-corner-all"></textarea>
    <div id="charCount"></div></fieldset>
  </form>
</div>

When I clicked the SMS link, this script drove the dialog and wrote the entered data into the LeapMessages list using SPServices.

dialogDiv.dialog({
  autoOpen : false,
  height : 300,
  width : 500,
  modal : true,
  buttons : {
    "Send Message" : function () {
      var bValid = true;
      allFields.removeClass("ui-state-error");
      bValid = bValid && checkLength(phoneNumber, "Phone number", 10);
      bValid = bValid && checkRegexp(phoneNumber, /^([0-9])+$/i, "Phone number can only contain digits.");
      // From jquery.validate.js (by joern), contributed by Scott Gonzalez: http://projects.scottsplayground.com/email_address_validation/
      if (bValid) {
        // Send the SMS message
        $().SPServices({
          operation : "UpdateListItems",
          async : false,
          batchCmd : "New",
          listName : "LeapMessages",
          valuepairs : [
            ["ReceiverMobileNumber", "+1" + phoneNumber.val()],
            ["Message", encodeXml(messageText.val())]
          ],
          completefunc : function (xData, Status) {}
        });
        $(this).dialog("close");
      }
    },
    Cancel : function () {
      $(this).dialog("close");
    }
  },
  close : function () {
    allFields.val("").removeClass("ui-state-error");
  }
});

There are a few helper functions referenced above, and here they are:

var loadedSMS = false;

var dialogDiv = $("#dialog");
var phoneNumber = $("#phoneNumber"),
messageText = $("#messageText"),
allFields = $([]).add(phoneNumber).add(messageText),
tips = $(".validateTips");

function checkLength(o, n, num) {
  if (o.val().length > num || o.val().length < num) {
    o.addClass("ui-state-error");
    updateTips(n + " must be  " + num + " digits.");
    return false;
  } else {
    return true;
  }
}

function checkRegexp(o, regexp, n) {
  if (!(regexp.test(o.val()))) {
    o.addClass("ui-state-error");
    updateTips(n);
    return false;
  } else {
    return true;
  }
}

function updateTips(t) {
  tips.text(t).addClass("ui-state-highlight");
  setTimeout(function () {
    tips.removeClass("ui-state-highlight", 1500);
  }, 500);
}

function countChars() {
  var messageLen = messageText.val().length;
  var errorClass = messageLen > 160 ? "class='ui-state-error'" : "";
  $("#charCount").html("You have used <span " + errorClass + " >" + messageLen + "</span> of 160 characters");
}
messageText.keyup(function () {
  countChars();
});

I decided to add one last piece of functionality. I couldn’t figure out how frequent the Twitter polling was, but when there was a new tweet in any any of the streams, I wanted to highlight it. To do this, I added this bit of script. It ran every three seconds to see if anything new had shown up, and if it had, it highlighted the counter at the top of each Twitter stream.

// Show tweet counters
setInterval("countTweets()", 3000);

function countTweets() {
  $("iframe[id^='twitter-widget-']").each(function () {
    var tweetCount = $(this).contents().find("li.tweet").length;
    var thisCounter = $(this).prev(".tweet-counter");
    if (thisCounter.length === 1) {
      var currCount = thisCounter.html();
      if (tweetCount != currCount) {
        thisCounter.addClass("ui-state-highlight");
        setTimeout(function () {
          thisCounter.removeClass("ui-state-highlight", 1500);
        }, 10000);
      }

      thisCounter.html(tweetCount);
    } else {
      $(this).before("<div class="tweet-counter">" + tweetCount + "</div>");
    }
  });
}

The Magic button is just a div. Yes, I violated best practices by making it a div instead of a real button. Don’t try this at home.

<div class="showSharePoint">Magic</div>

The Magic button contains the reveal. When I clicked on it, this script ran, unveiling the fact that the page was, in fact, a SharePoint page. There were very few oohs or aaahs that I could hear, which was a little disappointing, but hey, maybe I pushed it too fast or something.

// Set up the Magic button
$("div.showSharePoint").click(function () {

  var thisValue = $(this).text();

  if (thisValue == "Magic") {
    $("#RibbonContainer").hide();
    $("#s4-ribbonrow").slideDown(5000);
    $("#RibbonContainer").slideDown(5000, function () {
      $(this).fadeIn(1000)
    });
    $(".s4-titlerowhidetitle").fadeIn(5000);
    $("#s4-leftpanel").fadeIn(5000);
    $("#MSO_ContentTable").animate({
      "margin-left" : "150px"
    }, 5000, function () {
      // animation complete
    });
    $(this).text("No Magic");
  } else {
    $("#RibbonContainer").slideUp(5000, function () {
      $(this).fadeOut(1000)
    });
    $("#s4-ribbonrow").slideUp(5000);
    $(".s4-titlerowhidetitle").slideUp(5000);
    $("#s4-leftpanel").hide();
    $("#MSO_ContentTable").animate({
      "margin-left" : "0px"
    }, 5000, function () {
      // animation complete
    });
    $(this).text("Magic");

  }

});

So there you have it. I’m sure I’ve left some bits and bobs out of this in trying to make it consumable here, but I think I’ve gotten most of the important parts. All in good fun, and hopefully it got the message across that SharePoint doesn’t have to look like SharePoint and that we can do useful social stuff in SharePoint in many cool ways.

I’ve thought of a few neat things we could do with this, like storing the snippets in a SharePoint list and letting the user select which ones they want to see in their version of the page, dragging and dropping the streams into the order they like, and saving their settings for when they return. The possibilities with this stuff are really endless, depending on what you want to accomplish.

Have fun!

3-11-2013 11-47-29