Capturematic: Leveraging Mobile Templates in a Backbone.js App

Capturematic is an iOS app that lets you post a photo, audio or video to any Salesforce record with a Chatter feed; it's a great example of a simple hybrid mobile app that accesses device functionality - in this case, the camera and microphone. In this blog entry I focus on the new Salesforce Mobile Templates, which provide the app with a modern mobile look-and-feel.

Capturematic (GitHub repo) is an iOS app that lets you post a photo, audio or video to any Salesforce record with a Chatter feed; it’s a great example of a simple hybrid mobile app that accesses device functionality – in this case, the camera and microphone. You can see the app in action in this short video:

//www.youtube.com/watch?v=tU1sOW-G95A

Capturematic uses Cordova to access device features and Backbone.js as a model/view framework, but in this blog entry I’ll focus on the new Salesforce Mobile Templates, which provide the app with a modern mobile look-and-feel. At present, Capturematic is only available as source code, but I may submit it to the AppStore if there is sufficient demand.

Capturematic’s source is located in a single file, index.html, that is loaded after the Mobile SDK has authenticated the user. I’ll reproduce sections of code here, but you’ll probably find it useful to have that file open for reference.

Page Setup

The first thing you’ll notice, right at the top of the file, is the initial <meta> tag:

<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0; user-scalable=no" />

In a mobile browser, such as Safari on iOS, page content is laid out on the viewport, which can be larger or smaller than the visible area. When you view web pages on Safari that are not optimized for mobile, the viewport is typically larger than the screen, and you pan and zoom around it using touch gestures. In this <meta> tag, we explicitly specify that the viewport is the same width as the device screen, content is not scaled, and the user cannot zoom in on the page content – we want our app to behave more like an app than a web page. Next, you’ll see references to two stylesheets; app.css is the standard stylesheet for the Mobile Templates, while style.css defines some custom styles for Capturematic:

<link rel="stylesheet" href="resources/css/app.css">
<link rel="stylesheet" href="resources/css/style.css">

Looking at style.css for a moment, you can see how I’ve extended the Mobile Templates to add styling for an icon-panel class (copied from the template’s detail-view-action-panel class and modified from vertical to horizontal orientation), and sliding pages with CSS transitions, inspired by Christophe Coenraets’ PhoneGap Tutorial.

Scroll down index.html, to the set of <script> tags that load jQuery, Cordova, etc, and you’ll notice that the app loads the Mobile Templates JavaScript library, main.min.js. This code implements dynamic template components such as the Map and Carousel.

Debugging

Moving on down index.html, you’ll see the following code:

// Log JS errors to Cordova console
window.onerror = function(message, url, lineNumber) {
  logToConsole("Error: "+message+" in "+url+" at line "+lineNumber);
};

The window.onerror event handler causes any JavaScript errors, such as undefined objects, to be logged to the Xcode debug console, greatly simplifying debugging!

HTML Content

Skipping down to the <body>, we see Capturematic’s HTML markup. As a single-page application, Capturematic contains a top-level <div> element that acts as a container for dynamic content. The <div> is initialized with a ‘loading’ message while the app starts up and loads data.

The remaining markup is a series of Underscore templates. Three of the templates represent ‘pages’ in the app – Objects, Records, and Record Detail; the remaining two are list elements that are repeated on the pages – Object and Record.

The list of Force.com object types is rendered via objects-template. Let’s look at it in detail:

<script type="text/template" id="objects-template">
  <header>
    <h1>Objects</h1>
  </header>
  <div class="app-content">
    <section>
      <div class="content">
        <p>Select an object, then a record, then capture photos, audio or video to post to its Chatter page:</p>
      </div>
    </section>
    <ul id="object-list" class="list-view right-one-icons">
    </ul>
  </div>
</script>

If you’ve already looked at the Mobile Templates, you’ll recognize the structure here. There is a page header, a <section> containing some text, and a list view. This structure, and the CSS classes such as app-content, content, list-view and right-one-icons, produce an attractive mobile look and feel for the object list:

The list view is populated by a Backbone view, app.ObjectsView, which renders the Object list items via object-template:

<script type="text/template" id="object-template">
  <a href="#<%= name %>" class="content">
    <h2><%- label %></h2>
  </a>
  <div class="list-view-icons">
    <span class="icon-right-arrow">&nbsp;</span>
  </div>
</script>

Here you can see eRuby-style variable interpolation. app.ObjectsView iterates over the list of object types retrieved from Force.com, creating a new list item for each one, combining the template with the object metadata. You can see where the name and label fields are substituted into the HTML on the second and third lines respectively. The <%= name %> syntax causes the object name (e.g. Account, or Merchandise__c) to be used verbatim, while <%- label %> HTML-escapes label text, so labels containing characters such as ‘&’ or ‘<‘ won’t break the markup.

The record list page works in much the same way as the objects list, but the record detail page is worth examining in a little more detail:

<script type="text/template" id="record-detail-template">
  <header>
    <div class="main-menu-button main-menu-button-left">
      <a class="left-arrow">&nbsp;</a>
    </div>
    <h1>Capture</h1>
  </header>
  <div class="app-content">
    <div class="detail-view-header">
      <div class="content">
        <h1><%- Name %></h1>
      </div>
    </div>
    <div class="content">
      <section>
        <p>Capture media and post to Chatter for <%- Name %></p>
        <h2>Message</h2>
        <div class="form-control form-control-textarea">
          <textarea id="message" rows="4"></textarea>
        </div>
      </section>
      <section>
        <div class="icon-panel">
          <a href="#" class="icons-tile-camera get_picture">&nbsp;</a>
          <a href="#" class="icons-tile-mic capture_audio">&nbsp;</a>
          <a href="#" class="icons-tile-video capture_video">&nbsp;</a>
        </div>
      </section>
    </content>
  </div>
</script>

The record detail page shares many structural elements, such as the app-content and content <div>‘s, with the object list page, but there are some new concepts here.

Look at the link in the page header – the <a> element doesn’t contain an href attribute, or any content, apart from a non-breaking space! Take a quick look in app.css and you’ll see that the left-arrow class is styled with a background image and size:

header .main-menu-button a.left-arrow {
  background-image: url("../images/icons/left-arrow-white.png");
  background-size: 19.5px 28.5px;
}

By using the left-arrow style here and in the record list page, we keep the app DRY by having a single location for the UI element’s look-and-feel.

Similarly, all back buttons share the same logic. We avoid mixing JavaScript with HTML markup by defining a single click handler for the left-arrow class:

// Register event listener for back button throughout the app
$('.app-wrapper').on('click', '.left-arrow', function(event) {
  window.history.back();
  return false;
});

The record detail page uses the same interpolation for the record name, and more Mobile Template classes, form-control and form-control-textarea, to style the <textarea> input element. You can see the custom classes here, too – icon-panel is a horizontal layout of icon buttons for capturing photo, audio and video. The result is an attractively rendered detail page:

Todo

I could take Capturematic in any of a number of possible directions – here are a few examples:

  • Binary distribution via the Apple AppStore
  • Android version
  • Move from Backbone.Force to the Mobile SDK 2.0’s SmartSync.js
  • Show previously uploaded media content – or perhaps the entire Chatter feed for the record
  • Compress audio data, saving it as MP3 rather than WAV format

Let me know in the comments how you think I should prioritize these, or if you think of more, and I’ll blog the process.

Conclusion

I hope this post has demonstrated the potential of the Salesforce Mobile Templates. As well as the basic elements I used in Capturematic, there are many more dynamic components – the Mobile Templates site walks through the current palette – and you’re free to modify and extend the Mobile Templates for your purposes – they’re all open sourced under the Apache 2.0 license. Let us know if you build a cool mobile Force.com app, and we might just feature it in our Mobile App Gallery!

Leave your comments...

Capturematic: Leveraging Mobile Templates in a Backbone.js App