Skip to content

Latest commit

 

History

History
1222 lines (936 loc) · 65.6 KB

ch11_jquerymobile.asciidoc

File metadata and controls

1222 lines (936 loc) · 65.6 KB

jQuery Mobile

According to jquerymobile.com, jQuery Mobile is a HTML5-based user interface system designed to make responsive web sites and apps that are accessible on all smartphone, tablet and desktop devices. But jQuery Mobile was mainly created for developing Web applications for smaller screens.

To start learning jQuery Mobile you need to know HTML, JavaScript, CSS, and jQuery. In some publications you may see the statements that you could start using jQuery Mobile knowing only HTML. This is true till you’ll run into the first unexpected behavior of your code, which will happen pretty soon in one of the Web browsers (take the statements about being a cross-browser framework with a grain of salt too). After that you need to add some event listeners, scripts, and start debugging.

Where to get jQuery Mobile

The Web site of jQuery Mobile has all you need to start using this library. you can find lots of learning materials under the Demos section - they have tutorials, API reference, and samples of use. The Download section contains the links for the library itself.

There are two ways of including jQuery Mobile in the source code of your application: either download and uncompress the zip file in your local directory and specify this location in the source code of your application or include the URLs of the CDN-hosted files. Visit the jQuery Mobile Download page for the up-to-date URLs.

In our code samples we’ll be adding the following code snippets, which in gzipped format will make our application only 90Kb "heavier":

<link rel="stylesheet" href="http://code.jquery.com/mobile/1.3.1/jquery.mobile-1.3.1.min.css" />
<script src="http://code.jquery.com/jquery-1.9.1.min.js"></script>
<script src="http://code.jquery.com/mobile/1.3.1/jquery.mobile-1.3.1.min.js"></script>

Organizing the Code

The UI of a jQuery Mobile application consists of a set of HTML documents where certain attributes are added to the regular HTML components. Your Web application will consist of pages, and the user’s mobile device will show one page at a time. After the mockup of your application is ready (see section "Prototyping with Balsamiq Mockups" below), you know how many pages your application will have and how to navigate between the pages. Let’s see how to define the content of each page in jQuery Mobile.

HTML5 specification includes an important feature - you can add to any HTML tag any number of custom non-visible attributes as long as they start with data- and have at least one character after the hyphen. In jQuery Mobile this feature is being used in a very smart way. For example, you can add an attribute data-role to the HTML tag <div> to specify that it’s a page with id Stats:

<div data-role="page" id="Stats">

The UI of your application will consist of multiple pages, but what’s important, jQuery Mobile will show them one page at a time. Let’s say your application consists of two pages (Stats and Donate), then HTML may be structured as follows:

    <body>
    <!--  Page 1    -->
		<div data-role="page" id="Donate">
			...
		</div>

	 <!--  Page 2    -->
		<div data-role="page" id="Stats">
			...
		</div>
	</body>

When this application starts, the user will see only the content of the page Donate since it was included in the code first. We’ll talk about defining navigation a bit later.

Note
The above code fragment is an example of a multi-page template, where a single HTML document contains multiple pages. An alternative way of organizing the code is to have the content of each page in a separate file or a single-page template, and you’ll see the example later in this chapter.

Let’s say you want a page to be divided into the header, content and the footer. Then you can specify the corresponding roles to each of these sections.

    <body>
    <!--  Page 1    -->
		<div data-role="page" id="Donate">

		  <div data-role="header" >...</div>
		  <div data-role="content" >...</div>
		  <div data-role="footer" >...</div>

		</div>

    <!--  Page 2    -->
		<div data-role="page" id="Stats">
			...
		</div>
	</body>

It’s not a must to split the page with the data roles header, content, and footer. But if you do, the code will be better structured and additional styling can be applied in the CSS based on these attributes.

Note
It would be a good idea to replace three <div> tags inside the Donate page with HTML5 tags <header>, <article>, and <footer> but during the learning stage this could have confuse you mixing up HTML5 <header> and jQuery Mobile data role header (the footer line might have looked confusion too).

Let’s say you want to add navigation controls to the header of the page. You can add to the header a container with a data-role="navbar". In the following code sample we’ll use the menus from the Save The Child application.

<!DOCTYPE html>
<html>
 <head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
   <link rel="stylesheet" href="http://code.jquery.com/mobile/1.3.1/jquery.mobile-1.3.1.min.css"/>
 </head>
 <body>

  <div data-role="page">
   <div data-role="header">
  	<h1>Donate</h1>
  	<div data-role="navbar">
  	  <ul>
  	  	<li>
  	  		<a href="#Who-We-Are">Who We Are</a>
  	  	</li>
  	  	<li>
  	  		<a href="#What-We-Do">What We Do</a>
  	  	</li>
  	  	<li>
  	  		<a href="#Where-We-Work">Where We Work</a>
  	  	</li>
  	  	<li>
  	  		<a href="#Way-To-Give">Way To Give</a>
  	  	</li>
  	  </ul>
  	</div>
   </div> <!-- header -->

  <div data-role="content" >
      The content goes here
  </div>

  <div data-role="footer" >
    The footer goes here
  </div>

  <script src="http://code.jquery.com/jquery-1.9.1.min.js"></script>
  <script src="http://code.jquery.com/mobile/1.3.1/jquery.mobile-1.3.1.min.js"></script>
 </body>
</html>

We’ll explain the meaning of the HTML anchor tags in the section "Adding Page Navigation below". Note the The <viewport> tag in the above example. It instructs the browser of the mobile device to render the content to a virtual window that has to be the same as the width of the device’s screen. Otherwise the mobile browser may assume that it’s a Web site for desktop browsers and will minimize the content of the Web site so the user would need to zoom out. Read more about it in the sidebar titled "The Viewport Concept" in Chapter 10.

Tip
You can find the list of all available jQuery Mobile data- attributes in the Data attribute reference from the online documentation.

The above code sample is a complete HTML document that you can test in your browser. If you’ll do it in your desktop Web browser, the Web page will look as in Viewing the document in Firefox.

fig 12 02
Figure 1. Viewing the document in Firefox

How Will It Look on Mobile Devices?

Any mobile Web developer wants to see how his Web application will look on mobile devices. There two major ways of doing this: either test it on a real device or use a software emulator or simulator. Let’s talk about the emulators - there are plenty of them available.

For example, you can use one of the handy tools like Ripple Emulator. This Chrome browser’s extension will add a green icon on the right side of the browser’s toolbar - click on it and enable Ripple to run in a Web Mobile default mode. Then select the mobile device from the dropdown on the left and copy/paste the URL of your HTML document into Chrome browser’s address bar. Viewing the document in Ripple Emulator shows how our Web page would be rendered on the mobile phone Nokia97/5800.

Note
There are emulators that target specific platform. For example, you can consider Android Emulator or use iOS simulator that comes with Apple’s Xcode IDE. Chrome Developer Tools has an emulator panel too. For Nokia emulators browse their developer’s forum. Blackberry simulators are here. Microsoft also offers an emulator for their phones. You can more detailed list of various emulators and simulators in the O’Reilly book "Programming the Mobile Web, 2nd Edition" by Maximiliano Firtman.
fig 12 03
Figure 2. Viewing the document in Ripple Emulator

Using emulators really helps in the development. Ripple emulates not only the screen resolutions, but some of the hardware features as well (simulators usually simulate only the software). For example, you can test accelerometer by using the corresponding menu item under Devices (top left on Viewing the document in Ripple Emulator) or GEO Location under Settings (top right on Viewing the document in Ripple Emulator). But keep in mind that emulators run in in your desktop browser, which may render the UI not exactly the same way as a mobile browser running on the user’s mobile phone. For example the fonts may look a little different. Hence testing your application on a real device is highly recommended even though it’s impossible to test your Web application on thousands different devices people use.

If you can afford, hire real mobile users carrying different devices. You can do it at Mob4Hire testing as service (TaaS) Web site. The good news is that creators of jQuery Mobile use about 70 physical devices for testing of their UI components, but still, you may want to see how your application looks and feels on a variety devices.

If you want to see how your application looks on a real device that you own, the easiest way is to deploy your application on a Web server with a static IP address or a dedicated domain name. After the code is modifies, you need to transfer the code to that remote server and enter its URL in the address bar of your mobile device browser.

If you’re developing for iOS on MAC OS X computer, the procedure is even easier if both devices are on the same Wi-Fi network. Connect your iOS device to your MAC computer via the USB input. In computer’s System Preferences click on Networks and select your Wi-Fi connection on the left - you’ll see the IP address of your computer on the right, e.g. 192.168.0.1. If your application is deployed under the local Web server, you can reach it from your iOS device by entering in its browser address bar the URL of your application using the IP address of your computer, e.g. http://192.168.0.1/myApp/index.html. For details, read this blog.

Tip
If your mobile application behaves differently than on real device, see if there is an option for remote debugging on the device for your platform. For example, in this document Google explains how to do a remote debugging in Chrome browser running on Android devices. The Web browser Safari 7 supports remote debugging on iOS devices, details here.

Styling in jQuery Mobile

You may not like the design of the navigation bar shown on Viewing the document in Firefox, but it has some style applied to it. Where the white letters on the black background are coming from? It happens because we’ve included the data-role="navbar" in the code. This is the power of the the custom data- attributes in action. Creators of the jQuery mobile included into their CSS predefined styling for different data- attributes including the inner buttons of the navbar.

What if you don’t like this default styling? Create your own CSS, but first see if you might like some of the off-the-shelf themes offered by jQuery Mobile. You can have up to 26 pre-styled sets of toolbars, content and button colors called swatches. In the code you’ll referr them as themes lettered from A to Z. Adding the data-theme="a" to the <div data-role="page"> will make change the look of the entire page. But you can use the data-theme attribute with any HTML element, not necessarily for the entire page or other container.

By default, the header and the footer use swatch "a", and the content area - swatch "c". To change the entire color scheme of Viewing the document in Ripple Emulator to swatch "a" (the background of the content area will become dark gray) use the following line:

  <div data-role="page" data-theme="a">

jQuery mobile has a tool ThemeRoller that allows you to create a unique combination of colors, fonts, backgrounds and shadows and assign it to one of the letters of the English alphabet (see Theme Roller).

fig 12 04
Figure 3. Theme Roller

You can learn about creating custom themes with ThemeRoller by visiting this URL.

Adding Page Navigation

In jQuery Mobile page navigation is defined by using the HTML anchor tag <a href="">, where the href attribute can either point at a page defined as a section in the same HTML document or at a page defined in a separate HTML document. Accordingly, you can say that that we’re using either a multi-page template or a single-page template.

Multi-Page Template

With multi-page template each page is a <div> (or other HTML container) with an id, and the href attribute responsible for navigation will include the hash tag followed by the corresponding id.

    <body>
    <!--  Page 1    -->
		<div data-role="page" id="Donate" data-theme="e">
			<h1>Donate</h1>

			<a href="#Stats">Show Stats</a>
		</div>

	 <!--  Page 2    -->
		<div data-role="page" id="Stats">
			<h1>Statistics<h1>
		</div>
	</body>

If you use multi-page document, the ID of the page with a hash (#) will be added to the URL. For example, if the name of the above document is navigation1.html, when the Stats page is open the browser’s URL may look like this:

Let’s say that the only way to navigate from the Stats page is to go back to the page Donate. Now we’ll turn the above code fragment into a working 2-page document with the Back button support. Both pages in the following HTML document have a designated areas with the data-role="header", and the Stats page has yet another custom property data-add-back-btn="true". This is all it takes to ensure that the Back button is displayed in the left side of the page header, and when the user will tap on it, the application will navigate to the Donate page.

<!DOCTYPE html>
<html>
 <head>
	<meta charset="utf-8">
	<meta name="viewport" content="width=device-width, initial-scale=1">
  <link rel="stylesheet" href="http://code.jquery.com/mobile/1.3.1/jquery.mobile-1.3.1.min.css"/>
 </head>
<body>
    <!--  Page 1    -->
 	  <div data-role="page" id="Donate">
 	  	<div data-role="header" >
 	  	  <h1>Donate</h1>
          </div>
 	  	<a href="#Stats">Show Stats</a>
 	  </div>

	 <!--  Page 2    -->
       <div data-role="page" id="Stats" data-add-back-btn="true">
       	<div data-role="header" >
       	  <h1>Statistics</h1>
           </div>
           Statistics will go here

       </div>

  <script src="http://code.jquery.com/jquery-1.9.1.min.js"></script>
  <script src="http://code.jquery.com/mobile/1.3.1/jquery.mobile-1.3.1.min.js"></script>

  </body>
</html>

The Stats page with the Back button shows a snapshot of the Ripple emulator after the user clicked on the link on the Donate page. The Statistics page now includes the fully functional Back button.

fig 12 05
Figure 4. The Stats page with the Back button
Note
The attribute data-add-back-btn works the same way in both the multi-page and single-page cases. The back button will appear only if the current page is not the first one and there is a previous page to navigate to.
Single-Page Template

Now let’s re-arrange the code of the above sample using a single-page template. We’ll create a folder pages, which can contain multiple HTML files - one per page. In our case, we’ll create there one file stats.html to represent the Statistics page. Accordingly, we’ll remove the section marked as Page 2 from the main HTML file. The stats.html will look as follows:

<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
	</head>
	<body>
		<div data-role="page" data-add-back-btn="true">
			<div data-role="header">
			  <h1>Statistics</h1>
      </div>

      <div data-role="content">
        Statistics data will go here
      </div>
  </body>
</html>

The main HTML file will contain only one home page, which is a Donate page in this example. The anchor tag will simply refer to the URL of the stats.html - there is no need to use hash tags or section ID any longer. In his case jQuery Mobile will load the stats.html using internal AJAX request. This is how the main page will look like:

<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
		<meta name="viewport" content="width=device-width, initial-scale=1">
        <link rel="stylesheet" href="http://code.jquery.com/mobile/1.3.1/jquery.mobile-1.3.1.min.css" />
	</head>
<body>
    <!--  Main page  -->
		<div data-role="page" id="Donate">
			<div data-role="header">
			  <h1>Donate</h1>
            </div>

    <!--  A Link to the second page  -->
			<a href="pages/stats.html">Show Stats</a>
		</div>

  <script src="http://code.jquery.com/jquery-1.9.1.min.js"></script>
  <script src="http://code.jquery.com/mobile/1.3.1/jquery.mobile-1.3.1.min.js"></script>

  </body>
</html>

Running this version of our simple two-page application will produce the same results and the second page will look exactly as in The Stats page with the Back button.

If you use single-page documents, the name of the file with the page will be added to the URL. For example, when the Stats page is open the browser’s URL may look like this:

Multi or Single-Page Template

So which template style should you use? Both have their pros and cons. If the code base of your application is large, use single-page template. The code will be split into multiple pages, will be easier to read and will give you a feeling of being modular without implementing any additional libraries for cutting the application into pieces. The home page of the application comes quicker because you don’t need to load the entire code base.

This all sounds good, but be aware that with single-page templates whenever you’ll navigate from one page to another your mobile device makes a new request to the server. They user will see the wait cursor until the to-page has not arrived to the device. Even if the size of each page is small, additional requests to the server are costlier with mobile devices as they need another second just re-establish a radio link to the cell tower. After the communication with the server is done, the phone lowers its power consumption. The new request to the server for loading the page will start with increasing the power consumption again. Hence using the multi-page template may provide smoother navigation.

On the other hand, there is a way to pre-fetch pages into the DOM even in a single-page mode so the number of the server request id minimized. This can be done either with the HTML attribute data-prefetch="true" or programmatically using $.mobile.loadPage(). You can also ask the browser to cache previously visited pages with $.mobile.page.prototype.options.domCache = true;.

So what’s the verdict? Test your application in both single and multi-page modes and see what’s work best.

Progressive Enhancement

Web developers use technique called progressive enhancement, especially in the mobile field. The idea is simple - first make sure that the basic functionality works in any browser, and then apply bells and whistles to make the application as fancy as possible using CSS and or framework-specific enhancements.

But what if you decide to go the opposite route and take a nice looking UI and remove its awesomeness? For instance, delete <script> and <link> tags from the above html file and open it in the Web browser - we are testing a situation when, for whatever reason, we need to remove the jQuery Mobile from our code base. The code still works! You’ll see the first page, clicking on the link will open the second page. You’ll lose the styling and that nice-looking Back button, but you can still use the browser’s Back button. The Web browser ignores custom data- attributes without breaking anything.

This wouldn’t be the case if we’d be using the multi-page template, where each page is a <div> or an <article> in the same HTML file. With multi-page template the Web browser would open all pages at once - one under another.

Here’s another example. With jQuery Mobile you can create a button in many ways. There are multiple examples in the Buttons section of product documentation. The code below will produce five buttons, which will look the same, just the labels are different:

<a href="http://cnn.com" data-role="button">Anchor</a>
<form action="http://cnn.com">
    <button>Click me</button>
    <input type="button" value="Input">
    <input type="submit" value="Submit">
    <input type="reset" value="Reset">
</form>

If you chose to use the anchor link with data-role="button" and then remove the <script> tag that includes the code of jQuery Mobile library, the anchor tag will still work as a standard HTML link. It won’t look as a button, but it will function as expected.

When you’re making a decision about using any particular framework or library, ask yourself a question, "How easy it is to remove the framework from the application code if it doesn’t deliver as expected". On several occasions the authors of this book were invited to help with projects, where the first task was removal of a wrongly-selected framework from the application code. Such surgery usually lasts at least two weeks. jQuery Mobile is non overly intrusive and is easily removable.

Persistent Toolbars

One of the ways to arrange navigation is to add persistent toolbars that never go away while your application is running. You can add such a toolbar in the footer or header area or in both. We’ll create a simple example illustrating this technique by adding a a navbar to the footer area of the application. Let’s say, your application has a starting page and four other pages that can be selected by the user. Four pages in the footer. shows the initial view of the application.

fig 12 06
Figure 5. Four pages in the footer

If the user taps on one of the four pages in the footer, the program has to replace the starting page with the selected one, and the title of the selected page in the footer has to be highlighted. If you’re reading the electronic version of this book you’ll see in Page 2 is selected that the rectangular area for Page #2 in the footer got the blue background. In the printed version of the book the different the background colors may not so obvious, but you have to trust us on this or run the code sample on your own. Besides, we’ll be highlighting the selected page in a similar way while working on the prototype of the Save The Child application as per the mockups shown in the section "Prototyping Mobile Version".

fig 12 07
Figure 6. Page 2 is selected

In jQuery Mobile implementing persistent toolbars is simple. The content of each of the page has to be located in a separate file and each of them has to have the footer and header with the same data_id. Below is the code of the file page2.html, but page1, page3, and page 4 look similar - check them out in the source code that comes with the book.

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
  </head>
  <body>
    <div data-role="page" data-add-back-btn="true">
      <div data-role="header" data-position="fixed"
           data-tap-toggle="false" data-id="persistent-header"> <!--(1)-->
        <h1>Page #2</h1>
      </div><!-- /header -->
      <div data-role="content" >
        <p>
          <b>Page #2</b> content
        </p>
      </div><!-- /content -->
      <div data-role="footer" data-position="fixed"
         data-tap-toggle="false" data-id="persistent-footer"> <!--(2)-->
        <div data-role="navbar">
          <ul>
            <li>
              <a href="page-1.html" data-transition="slideup">Page #1</a>   <!--(3)-->
            </li>
            <li>
              <a href="#" class="ui-state-persist">Page #2</a> <!--(4)-->
            </li>
            <li>
              <a href="page-3.html" data-transition="slideup">Page #3</a>
            </li>
            <li>
              <a href="page-4.html" data-transition="slideup">Page #4</a>
            </li>
          </ul>
        </div><!-- /navbar -->
      </div><!-- /footer -->
    </div><!-- /page -->
  </body>
</html>
  1. To prevent the toolbar from being scrolled away from the screen we use data-position="fixed". The attribute data-tap-toggle="false" disables the ability to remove the toolbar from the secreen by tapping on the screen.

  2. The footer of page1, page2, page3, and page4 will have the same data-id="persistent-footer".

  3. While replacing the current page with another one, apply the transition effect so the page appears by sliding from the bottom up: data-transition="slideup". Note that the anchor tags are automatically styled as buttons just because they are placed in the navbar container.

  4. Since the Page 2 is already shown on the screen, tapping on the button "Page 2" in the navigation bar should not change the page, hence href="". The class="ui-state-persist" makes the framework to restore the active state each time when the existing in the DOM page is shown. The file page3.html will have a similar anchor for the button "Page #3" and so on.

The code of the main page index.html is shown below - it also defines the header, content, and footer areas:

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width,initial-scale=1,
        user-scalable=no,maximum-scale=1">
    <title>Single-page template - start page</title>
    <link rel="stylesheet" href="http://code.jquery.com/mobile/1.3.1/jquery.mobile-1.3.1.min.css" />
  </head>
  <body>

    <div data-role="page">
      <div data-role="header" data-position="fixed"
            data-tap-toggle="false" data-id="persistent-header">
        <h1>Start page</h1>
      </div>

      <div data-role="content" >
        <p>
          Single Page template. Start page content.
        </p>
      </div>

      <div data-role="footer" data-position="fixed"
            data-tap-toggle="false" data-id="persistent-footer">
        <div data-role="navbar">
          <ul>
            <li>
              <a href="pages/page-1.html" data-transition="slideup">Page #1</a>
            </li>
            <li>
              <a href="pages/page-2.html" data-transition="slideup">Page #2</a>
            </li>
            <li>
              <a href="pages/page-3.html" data-transition="slideup">Page #3</a>
            </li>
            <li>
              <a href="pages/page-4.html" data-transition="slideup">Page #4</a>
            </li>
          </ul>
        </div><!-- /navbar -->
      </div><!-- /footer -->
    </div><!-- /page -->

    <script src="http://code.jquery.com/jquery-1.9.1.min.js"></script>
    <script src="http://code.jquery.com/mobile/1.3.1/jquery.mobile-1.3.1.min.js"></script>
  </body>
</html>
Tip
To avoid repeating the same footer in each HTML page, you may write a JavaScript function that will append the footer to each page on the pagecreate event. You can also consider using HTML templating to declare HTML fragments that are parsed on page load, but can be instantiated later on during the runtime. In particular, we can recommend you the Handlebars, which lets you build semantic templates easily.
Programmatic Navigation

The above code samples were illustration page navigation as a response to the user’s action. Sometimes you need to change pages programmatically as a result of certain event, and the method $.mobile.changePage() can do this.

This method requires at least one parameter - the string defining the change-to-page, for example:

$.mobile.changePage("pages/stats.html");

But you can also invoke this method with a second parameter, which is an object, where you can specify such parameters as data - the data to send with AJAX page request, changeHash - a boolean to control if the hash in the URL should be updated and some others. For example, the following code sample changes the page using post request (type: "post") and the the new page should replace the current page in the browser’s history (changeHash: false).

$.mobile.changePage("pages/stats.html", {
	type: "post",
	changeHash: false
});

Save The Child with jQuery Mobile

After the brief introduction to jQuery Mobile library we (and you) are eager to start hands-on coding. The mobile version of the Save The Child won’t show all the features of this application. It’ll be sliced into a set of screens (pages), and the user will see one page at a time.

Note
You can test the working jQuery Mobile version of our sample application at http://savesickchild.org:8080/ssc-jquery-mobile/.

Prototyping Mobile Version

It’s time to go back to Jerry, the designer and his favorite prototyping tool Balsamiq Mockups introduced in Chapter 3. Designs and layouts for each screen of the mobile version are shown below as one of the images taken from Balsamiq tool. This is not a complete set of images as it doesn’t include layouts for tablets. In this book we will test only the mobile devices with screen sizes of 640x960 and 320x480 pixels.

fig 12 10
Figure 7. The Starting page (portrait)
fig 12 11
Figure 8. The About page (portrait)
fig 12 12
Figure 9. The Who We Are section of About page (portrait)
fig 12 13
Figure 10. The Donate page (portrait)

The small screen version of the above Donate page illustrates a term Above the Fold used by Web designers. This term originated in the newspaper business where the first half of the folded newspaper contained the most important headlines - something that the potential buyer would notice immediately. In Web design the Above the Fold means the first page that the user can see without the need to scroll. But if with newspapers people know that there is something to read below the fold, in Web design people may not know that the scrolling could reveal more information. In this particular case, there is a chance that a user with a 320x480 screen may not immediately understand that to see the Donate he needs to scroll.

In general, it’s a good idea to minimize the number of form fields that the user must manually fill out. Invest into analyzing the forms used in your application. See you can design the form smarter: auto-populate some of the fields and show/hide fields based on the user’s inputs.

Tip
If you have a long form that has to be shown on a small screen, split it into several <div data-role="page"> sections all located inside the <form> tag. Arrange the navigation between these sections as it was done for for multi-page documents in the section "Adding Page Navigation" above.
fig 12 14
Figure 11. The Statistics page (portrait)
fig 12 15
Figure 12. The Events page (portrait)
fig 12 16
Figure 13. The Media page (portrait)
fig 12 17
Figure 14. The Share page (portrait)
fig 12 18
Figure 15. The Share/Photo page for Chapter 14 (portrait)
fig 12 19
Figure 16. The Login popup (portrait)
fig 12 20
Figure 17. After the user logged in

This prototype will be used for the developing both jQuery Mobile and Sencha Touch versions of our Save The Child application. We’ve also included the design for the page that will integrate with the photo camera of the device (see The Share/Photo page for Chapter 14 (portrait)) - this functionality will be implemented in the last chapter dedicated to hybrid applications.

All of the above images show UI layouts when the mobile device is in the portrait mode, but you should ask your Web designer to prepare the mockups for the landscape mode too. Below are the couple of snapshots prepared by our Web designer Jerry.

fig 12 21
Figure 18. The Donate page (landscape, 640x960)
fig 12 22
Figure 19. The Donate page (landscape, 320x480)
fig 12 23
Figure 20. The Statistics page (landscape, 640x960)
fig 12 24
Figure 21. The Statistics page (landscape, 320x480)
Tip
If you want to add a link that will offer to dial a phone number, use the tel: scheme, for example: <a href="tel:+12125551212">Call us</a>. If you want the phone to look like a button, add the attribute data-role="button" to the anchor tag.

The Project Structure and Navigation

This time the Save The Child project structure will look as in The project structure. We are using the singe-page template here. The index.html is the home page of our application. All other pages are located in the pages folder. The JavaScript code is in the folder js, and fonts, images and CSS file are in the folder assets. We’ll use the same JSON files as in the previous versions of this application, and they are located in the folder data.

fig 12 25
Figure 22. The project structure

Let’s start implementing navigation based using the techniques described earlier in the section "Persistent Toolbars". The source code of the index.html is shown below. Note that we moved the <script> tags with jQuery Mobile code from that end of the <body> tag to the <head> section to avoid a popup of a non-styled page on the initial load of the application.

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width,initial-scale=1,user-scalable=no,
       maximum-scale=1">
// (1)
    <meta name="apple-mobile-web-app-capable" content="yes">
    <meta name="apple-mobile-web-app-status-bar-style" content="black">

    <title>Save The Child</title>

    <link rel="stylesheet" href="http://code.jquery.com/mobile/1.3.1/jquery.mobile-1.3.1.min.css" />
    <script src="http://code.jquery.com/jquery-1.9.1.min.js"></script>
    <script src="http://code.jquery.com/mobile/1.3.1/jquery.mobile-1.3.1.min.js"></script>

    // (2)
    <link rel="stylesheet" href="assets/css/jqm-icon-pack-3.0.0-fa.css" />

    <link rel="stylesheet" href="assets/css/app-styles.css" /> // (3)
  </head>
  <body>

    <div data-role="page">
// (4)
      <div data-role="header" data-position="fixed" data-tap-toggle="false"
      data-id="persistent-header">
        <a href="pages/login.html" data-icon="chevron-down" data-iconpos="right"
        class="ui-btn-right login-btn" data-rel="dialog">Login</a>
        <h1><img class="header-logo" src="assets/img/logo-20x20.png" alt="Save The Child Logo"/> </h1>
      </div>
// (5)
      <div data-role="content" >
        <h2>Save The Child</h2>
        <p>
          <b>Start page</b> content.
        </p>
      </div>
// (6)
      <div data-role="footer" data-position="fixed" data-tap-toggle="false"
      data-id="persistent-footer">
        <div data-role="navbar" class="ssc-navbar">
          <ul>
            <li>
              <a href="pages/about.html" data-iconshadow="false"
              data-icon="info-sign"
              data-transition="slideup">About</a> // (7)
            </li>
            <li>
              <a href="pages/donate.html" data-iconshadow="false" data-icon="heart"
              data-transition="slideup">Donate</a>
            </li>
            <li>
              <a href="pages/stats.html" data-iconshadow="false" data-icon="bar-chart"
              data-transition="slideup">Stats</a>
            </li>
            <li>
              <a href="pages/events.html" data-iconshadow="false" data-icon="map-marker"
              data-transition="slideup">Events</a>
            </li>
            <li>
              <a href="pages/media.html" data-iconshadow="false" data-icon="film"
              data-transition="slideup">Media</a>
            </li>
            <li>
              <a href="pages/share.html" data-iconshadow="false" data-icon="share"
              data-transition="slideup">Share</a>
            </li>
          </ul>
        </div><!-- /navbar -->
      </div><!-- /footer -->
    </div><!-- /page -->
    <script src="js/app-main.js"></script>
  </body>
</html>
  1. The metatags to request the full screen mode and black status bar on iOS devices. The main goal is to remove the browser’s address bar. Some developers suggest JavaScript tricks like window.scrollTo(0,1); (Google on it for details). But we are are not aware of a reliable solution for a guaranteed full screen mode in Web applications on all devices.

  2. This project uses jQuery Mobile Icon Pack - an extension of standard jQuery Mobile icons.

  3. Our CSS will override some of the jQuery Mobile classes and add new styles specific to our application.

  4. The header shows a Login button and the application logo.

  5. The content of the main page should go here

  6. All the navigation buttons are located in the footer.

  7. jQuery Mobile includes a number of icons that you can use by specifying their names in the data-icon attribute (read the Note on icons below). The icon position is controlled by the attribute data-iconpos. If you don’t want to show text, use data-iconpos="notext".

The first take on SSC home page shows how the landing page of the Save The Child application will look in the Ripple Emulator. Run it and click on each of the buttons in the navigation bar.

fig 12 26
Figure 23. The first take on SSC home page

NOTE:

In this application we use icon fonts to be displayed on the navigation bar. The main advantage over using images for icons is that icon fonts are maintenance free. You don’t need to resize and redraw icons. The disadvantage of the icon fonts is that they are single-colored, but for the navigation bar buttons having multi-colored images is not important.

In the above code we’ve been using the jQuery Mobile Icon Pack that’s available on GitHub. It’s an adaptation of the Twitter Bootstrap’s Font Awesome for jQuery Mobile. If you need fancier images for your mobile application, consider using Glypish icons.

The content of our custom CSS file app-styles.css comes next.

/* First, we want to stop jQuery Mobile using it's standard images for icons. */

.ui-icon-plus, .ui-icon-minus, .ui-icon-delete, .ui-icon-arrow-r, .ui-icon-arrow-l,
.ui-icon-arrow-u, .ui-icon-arrow-d, .ui-icon-check, .ui-icon-gear,
.ui-icon-refresh, .ui-icon-forward, .ui-icon-back, .ui-icon-grid, .ui-icon-star, .ui-icon-alert,
.ui-icon-info, .ui-icon-home, .ui-icon-search, .ui-icon-searchfield:after, .ui-icon-checkbox-off,
.ui-icon-checkbox-on, .ui-icon-radio-off, .ui-icon-radio-on,
.ui-icon-email, .ui-icon-page, .ui-icon-question, .ui-icon-foursquare, .ui-icon-dollar,
.ui-icon-euro, .ui-icon-pound, .ui-icon-apple, .ui-icon-chat,
.ui-icon-trash, .ui-icon-mappin, .ui-icon-direction, .ui-icon-heart, .ui-icon-wrench,
.ui-icon-play, .ui-icon-pause, .ui-icon-stop, .ui-icon-person,
 .ui-icon-music, .ui-icon-wifi, .ui-icon-phone, .ui-icon-power,
 .ui-icon-lightning, .ui-icon-drink, .ui-icon-android {
  background-image: none !important;
}

/* Override the jQuery Mobile CSS class selectors with the icon fonts. Whenever you create custom icon, jQuery Mobile expects to find a class with the name starting with `.ui-icon-` and ending with the name of the icon, like `.ui-icon-donatebtn` . But in HTML attributes you'll be using it without this prefix, e.g. `data-icon="donatebtn"`. */

.ui-icon-arrow-l:before {
  content: "\f053";
  margin-top: 2px
}
.ui-icon-delete:before {
  content: "\f00d";
  margin-left: 3px;
  margin-top: -2px
}
.ui-icon-arrow-r:before {
  content: "\f054";
  padding-left: 2px;
}
.ui-icon-arrow-d:before {
  content: "\f078";
}
.ui-icon-home:before {
  content: "\f015";
}

.header-logo {
  vertical-align: middle;
  padding-right: 0.3em;
  margin-top: -2px;
}

/* Create some custom styles for the Save The Child application. */

.ssc-navbar .ui-btn-text {
  font-size: 0.9em
}

/* overwide, customize icons css */
.ssc-navbar .ui-icon {
  background: none !important;
  margin-top:2px !important;
}
/* jQM allows not more than 5 items per line in navbar.
 We need 6. Hence we should override the default CSS rule.
 Each block will occupy 1/6 of the width: 16.66%
 */
.ssc-navbar .ui-block-a {
  width:16.66% !important;
}
.ssc-navbar .ui-block-b {
  width:16.66% !important;
}

.ssc-grid-nav {
  display: block;
  text-align: center;
  border-top: 1px solid #c0c0c0;
  text-decoration:none;
  color: #555 !important;
  overflow: hidden;
  box-sizing: border-box
}
.ssc-grid-nav:nth-child(odd) {
  border-right: 1px solid #c0c0c0;
}
.ssc-grid-item-icon {
  display:block;
  font-size: 2em;
  padding-bottom: 0.5em
}

Selected Code Fragments

All the code that implements Save The Child with jQuery Mobile is available to download from the publisher of this book (see the URL in the Preface), and we’re not going to include all program listings here. But we will show and comment selected code fragments that illustrate various features of jQuery Mobile.

Grid Layouts

While testing this initial version of the Save The Child application, note that the content of the About and Share pages is implemented as in mockups shown on The About page (portrait) and The Share page (portrait), which looks like grids. jQuery Mobile has several pre-defined layouts that will allow showing the content as rows and columns. Keep in mind that on small devices you should avoid displaying grids with multiple rows and columns as the data there will be hardly visible. But in our case the grid will contain just four large cells.The source code of the share.html followed by brief comments comes next (the code of the about.html looks similar).

<!DOCTYPE html>
<html>
 <head>
   <meta charset="utf-8">
 </head>
 <body>

   <div data-role="page" data-add-back-btn="true" id="Share">
     <div class="ssc-grid-header" data-role="header" data-position="fixed"
     data-tap-toggle="false" data-id="persistent-header">
       <a href="login.html" data-icon="chevron-down" data-iconpos="right"
       class="ui-btn-right login-btn" data-rel="dialog">Login</a>
       <h1><img class="header-logo" src="../assets/img/logo-20x20.png"
       alt="Save The Child Logo"/></h1>
     </div>

     <div data-role="content" style="padding:0">
       <div class="ui-grid-a">                      // (1)

         <div class="ui-block-a">                   // (2)
           <a href="#" class="ssc-grid-nav">
           <span class="ssc-grid-item-icon ui-icon-twitter"></span>
           <br/>
           Share via Twitter</a>
         </div>
         <div class="ui-block-b">
           <a href="#" class="ssc-grid-nav">
           <span class="ssc-grid-item-icon ui-icon-facebook"></span>
           <br/>
           Share via Facebook</a>
         </div>
         <div class="ui-block-a">
           <a href="#" class="ssc-grid-nav">
           <span class="ssc-grid-item-icon ui-icon-google-plus"></span>
           <br/>
           Share via Google+</a>
         </div>
         <div class="ui-block-b">
           <a href="#" class="ssc-grid-nav">
           <span class="ssc-grid-item-icon ui-icon-camera"></span>
           <br/>
           Photo App</a>
         </div>
       </div>
     </div>

     <div class="ssc-grid-footer" data-role="footer" data-position="fixed" data-tap-toggle="false"
     data-id="persistent-footer">
       <div data-role="navbar" class="ssc-navbar">
         <ul>
           <li>
             <a href="about.html" data-iconshadow="false" data-icon="info-sign"
             data-transition="slideup">About</a>
           </li>
           <li>
             <a href="donate.html" data-iconshadow="false" data-icon="heart"
             data-transition="slideup">Donate</a>
           </li>
           <li>
             <a href="stats.html" data-iconshadow="false" data-icon="bar-chart"
             data-transition="slideup">Stats</a>
           </li>
           <li>
             <a href="events.html" data-iconshadow="false" data-icon="map-marker"
             data-transition="slideup">Events</a>
           </li>
           <li>
             <a href="media.html" data-iconshadow="false" data-icon="film"
             data-transition="slideup">Media</a>
           </li>
           <li>
             <a href="#" data-iconshadow="false" data-icon="share"
              class="ui-state-persist">Share</a>
           </li>
         </ul>
       </div><!-- /navbar -->
     </div><!-- /footer -->
   </div><!-- /page  -->
 </body>
</html>
  1. The grid from The About page (portrait) is implemented using jQuery Mobile multi-column layout using ui-grid classes (see explanations below).

  2. Each of the cells in the grid is classes by the ui-block-a for the first grid row and ui-block-b for the second one. Hence "Share via Twitter" is in the left cell, and "Share via Facebook is on the right".

There are four preset configurations for grids containing two, three, four, and five columns called ui-grid-a, ui-grid-b, ui-grid-c, and ui-grid-d respectively. The Stats and About screens split into four sections, which can be laid out in two columns with ui-grid-a. With two-column layout, each of the column gets 50% of the width, with three-column layout - about 33% et al.

Each of the cells is laid out with the class that’s named with ui-block- followed by the corresponding letter, e.g. ui-block-c for the cells located in the third column. Preset grid layouts is a fragment from jQuery Mobile documentation, and it serves as a good illustration of the grid presets.

fig 12 27
Figure 24. Preset grid layouts

The class .ui-responsive allows to set breakpoints to grids that are less than 35em (560px) wide.

Control Groups

In the Donation screen, there us a section to allow the user to select one of the donation amounts. This is a good example of a set of UI controls that belong to the same group. In the desktop version of the application we’ve been using radio buttons grouped by the same name attribute like <input type="radio" name = "amount" …​. Revisit Chapter 3 and you’ll find the complete code example in the section titled "The Donate Section".

jQuery Mobile has a concept of control groups that comes handy in grouping and styling components. The code looks very similar, but now it’s wrapped in the <fieldset> container with the data-role="controlgroup".

<div class="donation-form-section">
  <label class="donation-heading">Please select donation amount</label>

  <fieldset data-role="controlgroup" data-type="horizontal" id="radio-container">

    <input type="radio" name="amount" id="d10" value="10"/>
    <label for="d10">$10</label>
    <input type="radio" name="amount" id="d20" value="20" />
    <label for="d20">$20</label>
    <input type="radio" name="amount" id="d50" checked="checked" value="50" />
    <label for="d50">$50</label>
    <input type="radio" name="amount" id="d100" value="100" />
    <label for="d100">$100</label>

  </fieldset>
  <label class="donation-heading">...or enter other amount</label>

  <input id="customAmount" name="amount"  value="" type="text"
   autocomplete="off" placeholder="$"/>

jQuery Mobile will render this code as shown in Controlgroup for donation amount. The buttons are laid out horizontally because of the attribute data-type="horizontal". If you don’t like the default styling of the radio buttons input fields, feel free to specify the appropriate data-theme either for the entire group or for each input field.

fig 12 28
Figure 25. Controlgroup for donation amount
Dropdowns and Collapsibles

Having an ability to use the minimum amount of screen real estate is especially important in mobile applications. Such controls can drop down or popup a list with some information when the user taps on a smaller component. Controls that we know as comboboxes or dropdowns in the desktop applications look different on the mobile devices, but the good news is that you don’t need to do any special coding to display a fancy-looking dropdown on the iPhone shown on States dropdown in the Donate form. Just use the HTML tag <select>, and the mobile browser will render it with a native look on the user’s device.

fig 12 29
Figure 26. States dropdown in the Donate form

The bad news is that sometimes you don’t want the default behavior offered by the <select> element. For example, you may want to create a menu that shows a list of items. First, we’ll show you how to do it using a popup that contains a listview. The next code is taken from the jQuery Mobile documentation - it suggests to implement a listview inside a popup:

<a href="#popupMenu" data-rel="popup" data-role="button"
   data-transition="pop">Select Donation Amount</a>

 <div data-role="popup" id="popupMenu" >
   <ul data-role="listview" data-inset="true" style="min-width:210px;">
       <li data-role="divider">Choose the amount</li>
       <li><a href="#">$10</a></li>
       <li><a href="#">$20</a></li>
       <li><a href="#">$50</a></li>
       <li><a href="#">$100</a></li>
   </ul>
 </div>

Initially the screen will look as in Select Donation Amount before the tap - it’s an anchor styled as a button…​.

fig 12 31
Figure 27. Select Donation Amount before the tap

After the user taps on the Set Donation Amount the menu pops up and it’ll look as in Select Donation Amount after the tap.

fig 12 32
Figure 28. Select Donation Amount after the tap

Another way of creating dropdowns is by using so called collapsibles. If the data role of a container is set to be collapsible, the content of the container won’t be initially shown. It’ll be collapsed showing only its header with a default icon (the plus sign) until the user will tap on it.

<div data-role="collapsible" data-theme="b"
                             data-content-theme="c">
   <h2>Select Donation Amount</h2>

   <ul data-role="listview">
       <li><a href="#">$10</a></li>
       <li><a href="#">$20</a></li>
       <li><a href="#">$50</a></li>
       <li><a href="#">$100</a></li>

   </ul>
</div>

If you’ll test the above code in Ripple Emulator, the initial screen will look as on Select Donation Amount before the tap - it’s a <div> with the data-role=collapsible. Note that the this code sample also illustrates using different themes for the collapsed and expanded version of this <div>. If you are reading the electronic version of this book on a color display, the collapsed version will have the blue background: data-theme="b".

fig 12 33
Figure 29. Select Donation Amount before the tap

After the user taps on the Set Donation Amount the menu pops up and it’ll look as in Select Donation Amount after the tap. The icon on the header changes from the plus sign to minus.

fig 12 34
Figure 30. Select Donation Amount after the tap
Listviews

In the section on Collapsibles you saw how easy it was to create a nicely looking list (Select Donation Amount after the tap) with data-role="listview". jQuery Mobile offers many ways of arranging items in lists and we encourage you to pay a visit to the Listviews section in online documentation.

Each list item can contain literally any HTML elements. The media page of the Save The Child application uses listview to arrange videos in the list. Below is the code fragment from media.html:

<div data-role="header"> ...  </div>

iv data-role="content" >
<ul data-role="listview" data-theme="a" data-inset="true" id="video-list">
  <li data-icon="chevron-right">
    <a href="#popupHtmlVideo" data-rel="popup" id="video-1"> <img src="../assets/img/thumb-01.jpg" class="ui-liicon"
    alt=""/> <h3>The title of a video-clip</h3>
    <p>
      Video description goes here. Lorem ipsum dolor sit amet, consectetuer adipiscing elit.
    </p> </a>
  </li>
  <li data-icon="chevron-right">
    <a href="#ytVideo" data-rel="popup"> <img src="../assets/img/thumb-02.jpg" class="ui-liicon"
    alt=""/> <h3>The title of a video-clip</h3>
    <p>
      Video description goes here. Lorem ipsum dolor sit amet, consectetuer adipiscing elit.
    </p> </a>
  </li>
</ul>

</div>

<div data-role="footer"> ...  </div>

<!-- html5 video in a popup -->
      <div data-role="popup" id="popupHtmlVideo" data-transition="slidedown"
      data-theme="a" data-position-to="window" data-corners="false">
        <a href="#" data-rel="back" data-role="button" data-theme="a" data-icon="delete" data-iconpos="notext"
         class="ui-btn-right">Close</a>
        <video controls="controls" poster="../assets/media/intro.jpg" preload="metadata">
          <source src="../assets/media/intro.mp4" type="video/mp4">
          <source src="../assets/media/intro.webm" type="video/webm">
          <p>Sorry, your browser doesn't support the video element</p>
        </video>
      </div>

<!-- YouTube video in a popup -->
      <div data-role="popup" id="ytVideo" data-transition="slidedown" data-theme="a"
      data-position-to="window" data-corners="false">
        <a href="#" data-rel="back" data-role="button" data-theme="a" data-icon="delete" data-iconpos="notext"
         class="ui-btn-right">Close</a>
        <iframe id="ytplayer" src="http://www.youtube.com/embed/VGZcerOhCuo?wmode=transparent&hd=1&vq=hd720"
         frameborder="0" width="480" height="270" allowfullscreen></iframe>
      </div>
    </div>

This code uses an unordered HTML list <ul>. Each list item <li> contains three HTML elements: <a>, <p>, and <span>. The anchor contains a link to the corresponding video to show in a popup. The content of each popup is located in a <div data-role="popup">. The data-rel="popup" in the anchor means that the resource from href has to be opened as a popup when the user taps on this link.

The <div id="popupHtmlVideo"> illustrates how to include a video using HTML5 tag <video>, and <div id="ytVideo"> shows how to embed a Youtube video. Note that both of these <div> elements are placed below the footer, and jQuery Mobile won’t show them until the user taps on the links.

Note that jQuery Mobile listview is styled in a way that each list item looks like a large rectangle, and the user can tap on the list item with his finger without being afraid of touching the neighbor controls. There is no such problem with desktop applications because the mouse pointer has a lot better precision than a finger or even a stylus.

fig 12 35
Figure 31. Using listview in media.html
Note
The <video> tag has an attribute autoplay. But since some of the mobile users are being charged by their phone companies based on their data usage, you may not automatically start playing video until the user explicitly taps the button play. There is no such restrictions in the desktop browsers.
jQuery Mobile Events

jQuery Mobile Events can be grouped by their use. There are events that deal with the page life cycle. For detailed description of events read the Events section in the online documentation. We’ll just briefly mention some of the events available in jQurMobile.

You should be using $(document).on("pageinit") and not $(document).ready() because the former is triggered even for the pages loaded as result of AJAX calls while the latter won’t. Prior to pageinit two more events are being dispatched: pagebeforecreate and pagecreate - after these two the widget enhancement takes place.

The pagebeforeshow and pageshow events are happening right before or after the to-page is displayed. Accordingly, pagebeforehide and pagehide are dispatched on the from-page. The pagechange event is dispatched when the page is being changed as the result of the programmatic invocation of the changePage() method.

If you are loading an external page (e.g. a user clicked on a link <a href="externalpage.html">Load External</a>), expect two events: pagebeforeload and pageload (or pageloadfailed).

Touch events is another group of events that are dispatched when the user touches the screen. Depending on how the user touches the screen, your application may receive tap, taphold, swipe, swipeleft, and swiperight events. The tap event handlers may or may not not work reliably on iOS devices.

The touchend event may be more reliable. Create a combined event handler for click and touchend events and your code will work on both desktop and mobile devices, for example:

$('#radio-container .ui-radio').on('touchend click', function() {
  // the event handler code goes here
}

Orientation events are important if your code needs to intercept the moments when the mobile device changes orientation. This is when jQuery Mobile fires the orientationchange event. The event objectwill have a property orientation, which will have either portrait or landscape in it.

There is one event that you can use to set some configuration options for the jQuery Mobile itself. The name of this event is mobileinit, and you should call the script to apply overrides after the jQuery Core, but before jQuery Mobile scripts are loaded. Details in online documentation.

Adding JavaScript

So far we were able to get by with HTML and CSS only - jQuery Mobile library was doing its magic, which was very helpful for the most part. But we still need a place for Javascript - Save The Child application has several hundreds of lines of JavaScript code and we need to find it a new home. You’ll find pretty much the same code that we used in previous chapters to deal with login, donate, maps and stats. It’s located in the jquerymobile sample project in the file js/app-main.js.

You may also need to write some scripts specific to jQuery Mobile workflows because, in some cases, you may want to override certain behavior of this library. In such cases you’d need to write JavaScript functions to serve as event handlers. For example, jQuery Mobile has a restriction that you can put not more than five buttons on the navbar. But we need six. Just to remind you, the the footer contains an attribute data-role="navbar" and it has an unordered list ul with six <li> items (not shown below for brevity):

 <div data-role="footer" data-position="fixed" data-tap-toggle="false"
                         data-id="persistent-footer">
   <div data-role="navbar" class="ssc-navbar">
     <ul>
      ...
     </ul>
   </div>
 </div><

Run the application with six buttons in the navbar, and get ready for the surprise. You’ll see a footer with a two-column and three-row grid as shown in Using listview in media.html, which is a screen snapshot of a Ripple Emulator with open Chrome Developer Tools panel while inspecting the navbar element in the footer.

fig 12 36
Figure 32. Using listview in media.html

Take a look at the styling of the navbar. Our original <ul> HTML element didn’t include the class ui-grid-a. jQuery Mobile couldn’t find the predefined layout for a six-button navigational bar and "decided" to allocate is as ui-grid-a, which is a two column grid (see the section Grid Layouts above).

The CSS file app-styles.css (see section The Project Structure and Navigation) has the provision for giving 16.6% of the width for each of six buttons, but we need to programmatically remove that ui-grid-a, which jQuery Mobile injected into our code. We’ll do it in JavaScript in the handler for pagebeforeshow event. The next code snippet from app-main.js finds the ul element that includes ssc-navbar as one of the styles and removes the class ui-grid-a from this unordered list:

$(document).on('pagebeforeshow', function() {
  $(".ssc-navbar > ul").removeClass("ui-grid-a");

Now the 16.6% of width will take effect and properly allocate all six buttons in a row. This was an example of overriding unwanted behavior using JavaScript. The rest of the code contains familiar functionality from the previous sections. We won’t repeat it here, but will show you some of the code sections that are worth commenting.

$(document).on('pagebeforeshow', function() {

  $(".ssc-navbar > ul").removeClass("ui-grid-a");

  if ( typeof (Storage) != "undefined") {
    var loginVal = localStorage.sscLogin;         // (1)

    if (loginVal == "logged") {
      $('.login-btn').css('display', 'none');
      $('.logout-btn').css('display', 'block');
    } else {
      $('.login-btn').css('display', 'block');
    }
  } else {
    console.log('No web storage support...');
  }
});

  function logIn(event) {
    event.preventDefault();

    var userNameValue = $('#username').val();
    var userNameValueLength = userNameValue.length;
    var userPasswordValue = $('#password').val();
    var userPasswordLength = userPasswordValue.length;

    //check credential
    if (userNameValueLength == 0 || userPasswordLength == 0) {
      if (userNameValueLength == 0) {
        $('#error-message').text('Username is empty');
      }
      if (userPasswordLength == 0) {
        $('#error-message').text('Password is empty');
      }
      if (userNameValueLength == 0 && userPasswordLength == 0) {
        $('#error-message').text('Username and Password are empty');
      }
      $('#login-submit').parent().removeClass('ui-btn-active');
      $('[type="submit"]').button('refresh');
    } else if (userNameValue != 'admin' || userPasswordValue != '1234') {
      $('#error-message').text('Username or password is invalid');
    } else if (userNameValue == 'admin' && userPasswordValue == '1234') {
      $('.login-btn').css('display', 'none');
      $('.logout-btn').css('display', 'block');

      localStorage.sscLogin = "logged";          // (2)
      history.back();
    }

  }

  $('#login-submit').on('click', logIn);

   ...


   $(document).on('pageshow', "#Donate", function() {  // (3)
     ...
   }

   $(document).on("pageshow", "#Stats", function() {   // (4)
     ...
   }

$(document).on("pageshow", "#Events", function() {     // (5)

}
  1. The button Login is located on the header of each page, and it turns into the button Logout when the user logs in. When the user moves from page to page, the old pages are being removed from DOM. To make sure that the login status is properly set, we check if the variable sscLogin in the local storage has the value logged (see explanation below).

  2. When the user logs in, the program saves the word logged in the local storage and closes Login popup by calling history.back().

  3. The Donate form code is located in this function. No AJAX calls are being made in this version of the Save The Child application.

  4. The SVG charts are created in this function.

  5. The GeoLocation code that uses Google Maps API goes here

While experimenting with Save The Child application we’ve created one more version using the multi-page template just to get a feeling of how smooth transitioning between the pages will look like if the entire code base will be loaded upfront. Of course, the wait cursor between the pages was gone, but the code itself became less manageable.

Tip
Ripple Emulator described earlier in this chapter allows you to test the look and feel of the jQuery Mobile version of the Save The Child application on various iOS and Android devices. But again, nothing beats testing on real devices.

Summary

In this chapter you’ve got familiar with a simple to use mobile framework. We’ve been using its version 1.3.1, which works pretty stable, but it’s not a mature library just yet. You can still run into situations when a feature advertised in the product documentation doesn’t work (e.g. page prefetching breaks images). So be prepared to study the code of this library and do the fixes to the critical features on your own. But there is a group of people who are actively working on bug fixing and improving jQuery Mobile, and using it in production is pretty safe.

By now you should have a pretty good understanding of how to start creating user interface with jQuery Mobile and where to find more information. Find some time and read the entire online documentation on jQuery Mobile. The learning curve is not steep, but there is a lot to read if you want to become productive with jQuery Mobile.