Enhancing SharePoint 2010 for the iPad (SPSAusTX 2012)

Despite being marketed as an entertainment device rather than a mobile platform for business, the iPad continues to gain traction as a mobile device for the next generation business user. For some organizations, the rich user interaction and usability afforded by the iPad is a compelling reason to work towards cross-platform capability or iPad specific versions of line-of-business systems. In this session we’ll review custom iPad specific enhancements for SharePoint 2010, including changes to the user interface based on the orientation of the device. Presented at SharePoint Saturday Austin, TX (January 21, 2012).

Enhancing SharePoint 2010 for the iPad (SPSVB 2012)

Despite being marketed as an entertainment device rather than a mobile platform for business, the iPad continues to gain traction as a mobile device for the next generation business user. For some organizations, the rich user interaction and usability afforded by the iPad is a compelling reason to work towards cross-platform capability or iPad specific versions of line-of-business systems. In this session we’ll review custom iPad specific enhancements for SharePoint 2010, including changes to the user interface based on the orientation of the device. Presented at SharePoint Saturday Virginia Beach (January 7, 2012).

SharePoint Saturday Tampa

For anyone interested, here's the slide deck that I presented at SharePoint Saturday Tampa on June 11, 2011 on Enhancing SharePoint 2010 for the iPad.

Enhancing the SharePoint 2010 UI: Scripted Orientation Aware Content

In my previous post we looked at enhancing the SharePoint 2010 UI through CSS based orientation detection. In this post, we will take it one step further and use some client side script to detect orientation and output content accordingly.

The CSS approach utilizes orientation aware style sheets which are loaded based on the appropriate orientation of the device (in this case an iPad). While this approach is simple to implement, it's not necessarily the most robust solution or the most scalable solution. The CSS approach is best suited to deployment with your site's branded master page, when orientation detection is a big part of your design. What if you only wanted it on one or two pages of your site, if you don't have access to deploy a new master page, or if you want more advanced orientation detection?

An alternative approach is to use client side scripting to detect the device orientation and process contextual changes for specific orientations. Another advantage to a scripted approach is that we now have some more information from the browser. The CSS approach simply looks for portrait vs. landscape, while the scripted approach gives us an integer value of the device orientation (0, 90, 180, or -90). Note that the browser gives us a value of "-90" as opposed to the "270" you'd expect to see when talking about rotation.

So to get started I'm going to create two div's in my design, one with an ID of "OrientationAlert" which we'll use to tell the user that more content is available if they rotate the device, and another with an ID of "SampleContent" to contain the demo content.

HTML:

<div id="OrientationAlert">Rotate device to landscape to view additional content.</div>
<div id="SampleContent">Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aenean rutrum ligula sed diam porta eleifend vitae sodales nisl. Nam hendrerit sodales mattis. Vestibulum dictum, erat sit amet sodales dignissim, libero est vulputate sem, sit amet mollis justo sapien mattis dolor. In semper velit ut urna luctus pharetra. Cras pellentesque enim in massa laoreet mattis. Ut consequat, mi quis tempor ultrices, velit urna vestibulum metus, sed tempor nisl magna quis tellus. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Suspendisse id eros turpis, quis faucibus quam. Donec tempus pretium mollis. In posuere, magna sit amet facilisis porttitor, lorem libero pretium libero, ut tempus neque tortor vitae eros. Proin nec neque sapien, vel convallis nisl. Donec ut nulla at ligula semper laoreet sed quis metus. Vivamus pretium turpis sit amet nibh laoreet non interdum dui accumsan. Fusce mollis, velit eget lobortis vestibulum, metus est malesuada justo, ac tempus est eros et purus. Aliquam non leo nisl, nec viverra elit.</div>

Next we'll put in some Javascript to do the work. Note that we're also calling jQuery to simplify things; simply put the jQuery library somewhere in your site and link to the appropriate path.

Javascript:

<script type="text/javascript" src="/Style%20Library/jquery-1.4.2.min.js"></script><script type="text/javascript">// <![CDATA[
    // Boolean; is device an iPad or not
    var isiPad = navigator.userAgent.match(/iPad/i) != null;
    if (isiPad) { // Process only for iPads
        ProcessOrientation(window.orientation); // Process initial orientation
        window.onorientationchange = function() { // Process on orientation change
            ProcessOrientation(window.orientation);
        }

        function ProcessOrientation(curOrientation) {
            if (curOrientation == 0 || curOrientation == 180) {
                // Portrait Orientation
                $("#OrientationAlert").show();
                $("#SampleContent").hide();
            } else if (curOrientation == 90 || curOrientation == -90) {
                // Landscape Orientation
                $("#OrientationAlert").hide();
                $("#SampleContent").show();
            }
        }
    } else {
        $("#OrientationAlert").hide();
    }
// ]]></script>

So what exactly does this do? First things first, if you think back to the previous blog post, you'll remember that we had to do some HTML "if" statements to apply the right style sheets to avoid confusing IE. In this scenario, we're doing it differently and only applying the code to the iPad. Line 4 in the code block above scans the user agent string from the browser, looking for "iPad". It then sets the isiPad variable to true if "iPad" is found, or false. We then analyse that variable (at line 5) so that we can do certain things if we're on an iPad, and others if we're not.

In this scenario we're going to hide the sample content in portrait, and show it in landscape. Likewise, if that content is hidden, we're going to show the user the OrientationAlert text so they know there's more available to see if they turn the device. Finally, if they're on a PC (the "not iPad"/else part of the equation) we're just going to hide the user alert since they'll be seeing all of the content.

You'll notice that there's a function in there called "ProcessOrientation" that contains the nuts and bolts of what we're doing. Before we dig into that we need to understand how it gets called. Lines 6 through 9 do a couple things. First things first, we have to call "ProcessOrientation" as soon as the script is loaded so that we determine the initial orientation. We then create a function that calls "ProcessOrientation" and attach it to the window.onorientationchange event. This tells the browser to run "ProcessOrientation" every time the device orientation is changed.

Now onto ProcessOrientation()--this is the function that does the work. For the purposes of this post, I've combined the landscape and portrait modes (0 and 180, 90 and -90), but you could certainly do different things based on each possibility. We then simply use jQuery hide() and show() to either hide the content and show the instruction alert, or hide the instruction alert and show the content.

With this approach, the orientation of the device really can become an integral component to the user interface and navigation. As an example, you could show different list views based on if the device is rotated to the left or to the right.

Another important thing to note is that this solution can be deployed in a number of ways, such as directly including it in the markup of a masterpage, layout, or individual page, or by including with a content editor web part. So for those of you playing in a Tier1 environment where you can't deploy solutions, you can technically roll out a solution like this through the web GUI.

Enhancing the SharePoint 2010 UI: iPad Orientation Detection

I recently had a chance to sit down and rapid prototype some iPad UI Enhancements for SharePoint 2010. I had previously done some light orientation detection for the iPod and iPhone, but with the iPad there's a lot more power in utilizing orientation detection. As the iPad gains more traction in the business world I expect to see more and more requirements to make enterprise platforms [like SharePoint] usable on the iPad. With Microsoft's commitment to cross-browser functionality in SharePoint 2010 we're fortunate that SharePoint 2010 will render on the iPad without any customizations needed.

The typical approach to porting desktop content to a mobile device is to scale content down to fit it all within the mobile device's display. With orientation detection we can turn off specific regions of content, or change the layout completely in order to maximize on the screen real estate and mitigate the need to scale down content--relative to how the user is holding the device. If we use the iPad as an example, in landscape orientation the resolution is 1024 x 768 but when we move it to portrait orientation the resolution swaps to 768 x 1024 (~250 pixels less on the width). Again, typically we'd just scale everything down to compensate for that drop on horizontal screen real estate. With a platform like SharePoint, making things smaller inherently makes it more difficult to navigate and the two-finger horizontal scroll on the iPad isn't really all that intuitive. The solution is to detect the orientation of the device and restructure content accordingly.

Orientation Based Style Sheets
At the core of these examples is orientation based style sheets. The iPad allows us to attach style sheets to only be used for the listed orientation. To attach orientation aware style sheets, append the orientation to the media attribute.

HTML:

This method will apply the iPadPortrait.css style sheet when the device is portrait, and the iPadLandscape.css style sheet when the device is landscape. Make sure you put your style sheet link tags after the core SharePoint style sheets to ensure they override the out of the box styling. Modern browsers like Chrome will detect the orientation parameter and compare the window width to the height to determine which one to use; Internet Explorer will not do this, but rather add both of your style sheets. In order to ensure cross-platform compatibility we need to do a simple browser check so that we don't show IE both style sheets.

HTML:

<!--[if !IE]><!-->

<!--<![endif]-->
<!--[if IE]>
          <link rel="stylesheet" href="/Style%20Library/iPadLandscape.css" />
<![endif]-->
Hiding the Quick Launch in Portrait If all you want to do is hide content in a specific orientation, then you only need a style sheet for that orientation (vs. one for each). Styles in the loaded style sheet can override styles defined in the core css. For example, if you wanted to hide the quick launch in portrait mode you would simply load a portrait style sheet containing CSS to hide the quick launch bar. HTML:
#s4-leftpanel {
  display: none;
}
.s4-ca {
  margin-left: 0px;
}
**Changing Layout** If you want to "move" content based on orientation then you'll need two style sheets (one for each orientation), and a little bit of thinking on your layout. For this example we will place a navigation bar on the left of the screen in landscape mode, and make it in-line across the top of the screen in portrait mode. First things first, when creating your layout you'll need to make two navigation bars (one where you want it to be in landscape, the other where you want it in portrait). As an example, if you wanted one in a left column in landscape and one across the top in portrait you could do something like the following (including the OOTB SharePoint markup).
<table width="100%" border="0" cellspacing="0" cellpadding="4">
<tbody>
<tr>
<td id="_invisibleIfEmpty" class="iPadPortrait" colspan="2" valign="top" width="100%">
<ul class="iPadNavigation">
    <li>Chart 1</li>
    <li>Chart 2</li>
    <li>Chart 3</li>
    <li>Chart 4</li>
    <li>Chart 5</li>
    <li>Chart 6</li>
</ul>
</td>
</tr>
<tr>
<td id="_invisibleIfEmpty" class="iPadLandscape" valign="top" width="200" height="100%">
<ul class="iPadNavigation">
    <li>Chart 1</li>
    <li>Chart 2</li>
    <li>Chart 3</li>
    <li>Chart 4</li>
    <li>Chart 5</li>
    <li>Chart 6</li>
</ul>
</td>
<td id="_invisibleIfEmpty" valign="top" width="100%" height="100%">Standard SharePoint Zone</td>
</tr>
</tbody>
</table>

Obviously it's a bit more work to create two navs, but if you're writing the markup through script or through a DVWP then the additional work is negligible. You'll notice that the markup for the two is identical, the only change being that the parent cell has a class of either iPadPortrait or iPadLandscape. This is done intentionally so that we can re-use styling between the two navs; this ensures that you don't have to manage baseline button looks in two places.

.iPadPortrait .iPadNavigation, .iPadLandscape .iPadNavigation {
  width: 100%;
  padding: 0;
  margin: 0;
  text-align: center;
  list-style-type: none;
}
.iPadPortrait .iPadNavigation li, .iPadLandscape .iPadNavigation li {
  margin: 4px;
  border: 1px solid #333;
  font-weight: bold;
  padding: 8px 0;
  font-size: 12px;
}

In our individual orientation style sheets we then add the appropriate CSS to hide the elements used in the opposite orientation, and make any changes to the base button styles. Note the addition of the display parameter on the portrait navigation CSS to make our button elements display inline vs. stacked.

iPadPortrait.css:

.iPadLandscape {
    display: none; /*hides all "Landscape" classes*/
}
.iPadPortrait .iPadNavigation li {
  display: inline-block;
  width: 130px;
}

iPadLandscape.css:

.iPadPortrait {
    display: none; /*hides all "Portrait" classes*/
}
.iPadLandscape .iPadNavigation li {
  width: 150px;
}

Site-wide Orientation Support
You can easily use these methods along with your SharePoint branding strategy to roll out layout changes that inherit across the platform. In the final example in the video above, I've appended the "iPodLandscape" class to an entire zone in the SharePoint layout. This allows users to add web parts, content and other media in a zone which will automatically hide itself when the iPad is in portrait mode.

Going Further
The orientation based style sheets are great for the detection of portrait vs. landscape but we also have the ability to take it a step further. The value of window.orientation will give you a numerical value of the orientation (0, -90, 90, or 180). This allows you to also detect if the device is upside down, as opposed to simply portrait or landscape. You can listen for orientation change by appending the "onOrientationChange" attribute to the <body> tag, or by using jQuery.