jQuery Mobile - Enterprise Considerations - Enterprise Web Development (2014)

Enterprise Web Development (2014)

Part II. Enterprise Considerations

Chapter 11. jQuery Mobile

According to jquerymobile.comjQuery Mobile is an HTML5-based user interface system designed to make responsive websites 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 might see statements extolling how you can start using jQuery Mobile knowing only HTML. This is true until you run into the first unexpected behavior of your code, which you’ll inevitably encounter 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 and scripts, and start debugging.

Obtaining jQuery Mobile

The jQuery Mobile website has all you need to start using this library. You can find lots of learning materials in the Demos section: tutorials, an API reference, and samples. The Download section contains 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 content delivery network (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 90 KB larger:

<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, and 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 Prototyping the Mobile Version), you know how many pages your application will have and how to navigate among them. Let’s see how to define the content of each page in jQuery Mobile.

The HTML5 specification includes an important feature: you can add to any HTML tag any number of custom nonvisible 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 the ID Stats:

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

The UI of your application will consist of multiple pages, but what’s important is that jQuery Mobile will show one page at a time. Let’s say your application consists of two pages (Stats and Donate); the 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 because it is included in the code first. We’ll talk about defining navigation a bit later.

NOTE

The preceding code fragment is an example of a multipage template, a single HTML document containing 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 an example later in this chapter.

Let’s say you want a page to be divided into the header, content, and the footer. You can then 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 the three <div> tags on the Donate page with the HTML5 tags <header>, <article>, and <footer>. However, during this learning stage, this could have confused you, because it’s easy to mix up the HTML5 <header> and jQuery Mobile data role header. (The footer line might have looked confusing, 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 data-role="navbar". In Example 11-1, we’ll use the menus from the Save The Child application.

Example 11-1. Adding a navigation bar

<!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. For now, note the <viewport> tag in the preceding example. It instructs the browser of the mobile device to render the content to a virtual window that has to have the same width as that of the device’s screen. Otherwise, the mobile browser might assume that it’s a website for desktop browsers and will minimize the content, requiring the user to zoom out. Read more about it in the sidebar The Viewport Concept in Chapter 10.

TIP

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

The preceding code sample is a complete HTML document that you can test in your browser. If you use desktop web browser, the web page will look like Figure 11-1.

Viewing the document in Firefox

Figure 11-1. Viewing the document in Firefox

Seeing How It Looks 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 available.

For example, you can use one of the handy tools such as the Apache Ripple emulator. This Chrome browser extension adds a green icon on the right side of the browser’s toolbar; click it to enable Ripple to run in its Web Mobile default mode. Next, select the mobile device from the drop-down on the left, and then copy and paste the URL of your HTML document into the Chrome browser’s address bar. Figure 11-2 shows how our web page would be rendered on the mobile phone Nokia 97/5800.

NOTE

Some emulators target a specific platform. For example, you can consider Android Emulator or use the iOS simulator that comes with Apple’s Xcode IDE. Chrome Developer Tools has an emulator panel, too. For Nokia emulators, browse its developer’s forum. BlackBerry simulators are here. Microsoft also offers an emulator for its phones. You can find a more detailed list of various emulators and simulators in Programming the Mobile Web by Maximiliano Firtman (O’Reilly).

Viewing the document in the Ripple emulator

Figure 11-2. Viewing the document in the Ripple emulator

Using emulators really helps in 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 an accelerometer by using the corresponding menu item under Devices (at the upper left in Figure 11-2) or Geo Location under Settings (at the upper right in Figure 11-2). But keep in mind that emulators run in your desktop browser, which might render the UI in not exactly the same way as a mobile browser running on the user’s mobile phone. For example, the fonts might 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 the thousands of different devices people use.

If you can afford it, hire real mobile users carrying different devices. You can do this through the Mob4Hire testing as a service (TaaS) website. The good news is that creators of jQuery Mobile use about 70 physical devices for testing of their UI components, but still, you might want to see how your application looks and feels on a variety of 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 modified, 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 a Mac OS X computer, the procedure is even easier if both devices are on the same WiFi network. Connect your iOS device to your Mac computer via the USB input. In System Preferences, click Networks and select your WiFi connection on the left. You’ll see the IP address of your computer on the right (for example, 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 (for example, http://192.168.0.1/myApp/index.html). For details, read my blog post, “Hack: iPhone, USB, Macbook, Web Server.”

TIP

If your mobile application behaves differently than on a 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 remote debugging in a Chrome browser running on Android devices. The web browser Safari 7 supports remote debugging on iOS devices (details here).

Styling in jQuery Mobile

You might not like the design of the navigation bar shown in Figure 11-1, but it has some style applied to it. Where are the white letters on the black background coming from? They’re styled this way because we’ve included data-role="navbar" in the code. This is the power of the custom data- attributes in action. The creators of jQuery Mobile included in their CSS predefined styling for 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 whether you like some of the off-the-shelf themes offered by jQuery Mobile. You can have up to 26 prestyled sets of toolbars, content, and button colors called swatches. In the code, you’ll refer to them as themes lettered from A to Z. Adding data-theme="a" to <div data-role="page"> will change the look of the entire page. But you can use the data-theme attribute with any HTML element, not necessarily the entire page or other container.

By default, the header and the footer use swatch A, and the content area uses swatch C. To change the entire color scheme of Figure 11-2 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 you can use to create a unique combination of colors, fonts, backgrounds, and shadows and assign it to one of the letters of the alphabet (see Figure 11-3).

ThemeRoller

Figure 11-3. ThemeRoller

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 point at either a page defined as a section in the same HTML document or a page defined in a separate HTML document. Accordingly, you can say that we’re using either a multipage template or a single-page template.

Multipage template

With a multipage template (see Example 11-2) each page is a <div> (or other HTML container) with an ID. The href attribute responsible for navigation includes a hash character (#) followed by the corresponding ID.

Example 11-2. Organizing code with a multipage template

    <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 a multipage document, the ID of the page with a hash character will be added to the URL. For example, if the name of the preceding document is navigation1.html, when the Statistics page is open, the browser’s URL will look like this:

http://127.0.0.1/navigation1.html#Stats

Let’s say that the only way to navigate from the Statistics page is to go back to the Donate page. Now we’ll turn the preceding code fragment into a working two-page document with Back-button support. Both pages in the HTML document in Example 11-3 have a designated area with 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 displays at the left side of the page header, and that when the user taps on it, the application navigates to the Donate page.

Example 11-3. The Donate and Stats 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>

Figure 11-4 shows a snapshot of the Ripple emulator after the user clicks the link on the Donate page. The Statistics page now includes the fully functional Back button.

The Statistics page with the Back button

Figure 11-4. The Statistics page with the Back button

NOTE

The attribute data-add-back-btn works the same way in both the multipage and single-page cases. The Back button appears 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 rearrange the code in Example 11-3 by using a single-page template. We’ll create a folder of pages, which can contain multiple HTML files—one per page. In our case, we’ll create 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 file is shown in Example 11-4.

Example 11-4. The HTML code of the Statistics web page

<!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 contains only one home page, which is the Donate page in this example. The anchor tag simply refers to the URL of stats.html; there is no need to use hash characters or section IDs any longer. In this case, jQuery Mobile loads stats.html by using an internal Ajax request.Example 11-5 shows the main page.

Example 11-5. The HTML of the main 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>

    <!--  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 produces the same results. The second page looks exactly like Figure 11-4.

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

http://127.0.0.1/pages/stats.html

Multipage 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 a 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 loads 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 navigate from one page to another, your mobile device makes a new request to the server. The user will see the wait cursor until the page arrives at the device. Even if the size of each page is small, additional requests to the server are costlier with mobile devices because they need another second just to re-establish a radio link to the cell tower. After communication with the server is done, the phone lowers its power consumption. However, a new request to the server for loading the page starts increasing power consumption again. Hence, using the multipage template might provide smoother navigation.

On the other hand, there is a way to prefetch pages into the DOM even in single-page mode such that the number of server requests is minimized. You can do this either with the HTML attribute data-prefetch="true" or programmatically by 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-page and multipage modes and see what works best.

PROGRESSIVE ENHANCEMENT

Web developers use a 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 the bells and whistles to make the application as fancy as possible by using CSS 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 the <script> and <link> tags from Example 11-5 and open it in a web browser. We are testing a situation in which, for whatever reason, we need to remove jQuery Mobile from our code base. The code still works! You’ll see the first page, and clicking the link opens 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 the custom data- attributes without breaking anything.

This wouldn’t be the case if we were using the multipage template, where each page is a <div> or an <article> in the same HTML file. With a multipage template, the web browser would open all pages at once—one below 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 the product documentation. The following code produces five buttons, which will look the same but have different labels:

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

When you’re making a decision about using any particular framework or library, ask yourself this question: “How easy is it to remove the framework from the application code if it doesn’t deliver as expected?” On several occasions, the authors of this book have been invited to help with projects in which the first task was to remove an erroneously selected framework from the application code. Such “surgery” usually lasts at least two weeks. jQuery Mobile is not overly intrusive and is easily removed.

Adding 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 navbar to the footer area of the application. Suppose that your application has a starting page and four other pages that can be selected by the user. Figure 11-5 shows the initial view of the application.

Four pages in the footer

Figure 11-5. Four pages in the footer

If the user taps one of the four pages in the footer, the program replaces the starting page with the selected one, and the title of the selected page in the footer becomes highlighted. If you’re reading the electronic version of this book, you’ll see in Figure 11-6 that the rectangular area for Page #2 in the footer has a blue background. In the printed version, the different background colors might not be 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 Prototyping the Mobile Version.

Page 2 is selected

Figure 11-6. Page 2 is selected

In jQuery Mobile, implementing persistent toolbars is simple. The content of each page has to be located in a separate file, and each page has to have a footer and header with the same data_id. Example 11-6 presents the code of the file page2.html, but page1page3, and page4 look similar; check them out in the source code that comes with this book.

Example 11-6. The file page2.html

<!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 view by tapping on the screen.

2

The footers of page1page2page3, and page4 have the same data-id="persistent-footer".

3

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

4

Because page 2 is already shown on the screen, tapping the Page #2 button 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 page existing in the DOM is shown. The file page3.html has a similar anchor for the Page #3 button, and so on.

Example 11-7 presents the code of the main page index.html. This code also defines the header, content, and footer areas.

Example 11-7. The main page with header, content, and footer sections

<!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 can write a JavaScript function that appends 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, during runtime. In particular, we can recommend Handlebars, which lets you build semantic templates easily.

Programmatic navigation

The preceding code samples illustrated page navigation as a response to the user’s action. Sometimes, you need to change pages programmatically as a result of certain events, 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. You can specify such parameters as data (the data to send with the Ajax page request), changeHash (a boolean to control if the hash in the URL should be updated), and others. Example 11-8 changes the page by using a post request (type: "post"), and the page should replace the current page in the browser’s history (changeHash: false).

Example 11-8. Changing page with Ajax post request

$.mobile.changePage("pages/stats.html", {

        type: "post",

        changeHash: false

});

Using jQuery Mobile for Save The Child

After the brief introduction to the jQuery Mobile library, we (and you) are eager to start hands-on coding. The mobile version of Save The Child won’t show all the features of this application. It will 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 link:http://savesickchild.org:8080/ssc-jquery-mobile.

Prototyping the Mobile Version

It’s time to go back to Jerry, our web designer, and his favorite prototyping tool, Balsamiq Mockups (to which you were introduced in Chapter 1). Designs and layouts for each screen of the mobile version are shown in this section as images taken from the Balsamiq tool. This is not a complete set of images because it doesn’t include layouts for tablets. In this book, we test only mobile devices with screen sizes of 640 x 960 and 320 x 480 pixels.

Figure 11-7 shows two versions of the starting page mockup in portrait mode. Figure 11-8 shows two versions of the About page mockups in portrait mode.

The Starting page (portrait)

Figure 11-7. The Starting page (portrait)

The About page (portrait)

Figure 11-8. The About page (portrait)

Figures 11-9 and 11-10 also show mockups in portrait mode; Figure 11-9 displays two versions of the Who We Are page, and Figure 11-10 depicts two versions of the Donate page.

The Who We Are section of the About page (portrait)

Figure 11-9. The Who We Are section of the About page (portrait)

Figure 11-10 illustrates a term Above the Fold used by web designers. This term originated in the newspaper business. It refers to the upper half of the first page of a broadsheet newspaper that has been folded for display and sale at a newstand. This is the section that is visible to passersby and therefore contains the most important headlines—something that a potential buyer would notice immediately. In web design, Above the Fold refers to the content on a web page that a user can see without needing to scroll. However, whereas newspaper readers know that there is more to see below the fold, when it comes to web pages, you need to keep in mind that visitors to your web page might not be aware that the scrolling could reveal more information. As it relates to our Save The Child web application, a user with a 320 × 480 screen might not immediately understand that to see the Donate button, she needs to scroll.

The Donate page (portrait)

Figure 11-10. The Donate page (portrait)

In general, it’s a good idea to minimize the number of form fields that the user must manually fill out. Invest in analyzing the forms used in your application. See if you can design the form smarter; for example, autopopulate some of the fields and show/hide fields based on user input.

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 multipage documents in the previous section, Adding Page Navigation.

The following images show more of Jerry’s mockups. Figure 11-11 shows two versions of the Statistics page in portrait mode. Note the highlighted Stats button indicating the active page.

The Statistics page (portrait)

Figure 11-11. The Statistics page (portrait)

Figure 11-12 shows two versions of the Events page mockups in portrait mode. Note the highlighted Events button indicating the active page.

The Events page (portrait)

Figure 11-12. The Events page (portrait)

Figure 11-13 shows two versions of the Media page mockups in portrait mode. The user has to click the video title to play it.

The Media page (portrait)

Figure 11-13. The Media page (portrait)

Figure 11-14 shows two versions of the Share page mockups in portrait mode. Jerry decided to divide the viewport into four areas. Each rectangle is a link to the corresponding page.

The Share page (portrait)

Figure 11-14. The Share page (portrait)

Figure 11-15 shows two versions of the Share Photo page mockups in portrait mode. Note the additional navigation bar at the bottom.

The Share/Photo page (portrait)

Figure 11-15. The Share/Photo page (portrait)

Figure 11-16 shows two versions of the Login page mockups in portrait mode. The Login panel is implemented as a pop-up window.

The Login pop-up (portrait)

Figure 11-16. The Login pop-up (portrait)

Figure 11-17 shows two versions of the Login page mockups in portrait mode after the Login pop-up is closed.

After the user logs in

Figure 11-17. After the user logs in

This prototype will be used for 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 device’s camera (see Figure 11-15); this functionality is implemented in Chapter 13.

All of these images show UI layouts when the mobile device is in portrait mode, but you should ask your web designer to prepare mockups for landscape mode, too. Figures 11-1811-1911-20, and 11-21 show snapshots in landscape mode that Jerry also prepared prepared for us.

The Donate page (landscape, 640 x 960)

Figure 11-18. The Donate page (landscape, 640 x 960)

The Donate page (landscape, 320 x 480)

Figure 11-19. The Donate page (landscape, 320 x 480)

The Statistics page (landscape, 640 x 960)

Figure 11-20. The Statistics page (landscape, 640 x 960)

The Statistics page (landscape, 320 x 480)

Figure 11-21. The Statistics page (landscape, 320 x 480)

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.

Project Structure and Navigation

This time the Save The Child project structure will look like Figure 11-22. We are using the singe-page template here. The index.html file 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 files are in the folder assets. We’ll use the same JSON files as in the previous versions of this application, which are located in the folder data.

Let’s start implementing navigation based on the techniques described earlier, in the section Adding Persistent Toolbars. The source code of index.html is shown in Example 11-9. Note that we moved the <script> tags with jQuery Mobile code from the <body> section to the <head>section to avoid a pop-up of a nonstyled page on the initial load of the application.

Example 11-9. The file index.html

<!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 meta tags to request the full-screen mode and a black status bar on iOS devices. The main goal is to remove the browser’s address bar. Some developers suggest JavaScript tricks such as window.scrollTo(0,1); (Google it for details). But we 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 icons that you can use by specifying their names in the data-icon attribute (more details are provided in the upcoming sidebar Icon Fonts). The icon position is controlled by the attribute data-iconpos. If you don’t want to show text, use data-iconpos="notext".

ICON FONTS

In this application, we use icon fonts for display 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. A disadvantage of using icon fonts is that they are single-colored, but for the navigation bar buttons, having multicolored images is not important.

In Example 11-9, we use 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 Glyphish icons.

The project structure

Figure 11-22. The project structure

Figure 11-23 shows how the landing page of the Save The Child application looks in the Ripple emulator. Run it and click each button in the navigation bar.

The first take on the Save The Child home page

Figure 11-23. The first take on the Save The Child home page

The content of our custom CSS file app-styles.css comes next, which you can see in Example 11-10.

Example 11-10. The file app-styles.css

/* First, we want to stop jQuery Mobile from using its standard images */

/* for icons. */

.ui-icon-arrow-l.ui-icon-alert.ui-icon-checkbox-off,

.ui-icon-dollar.ui-icon-wrench,

.ui-icon-plus.ui-icon-minus.ui-icon-delete.ui-icon-arrow-r,

.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-info.ui-icon-home.ui-icon-search.ui-icon-searchfield:after,

.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-euro.ui-icon-pound.ui-icon-apple.ui-icon-chat,

.ui-icon-trash.ui-icon-mappin.ui-icon-direction.ui-icon-heart,

.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 GitHub, 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 the mock ups shown in Figures 11-8 and 11-14, which look like grids. jQuery Mobile has several predefined layouts with which you can show the content as rows and columns. Keep in mind that on small devices, you should avoid displaying grids with multiple rows and columns because the data there will be hardly visible. But in our case, the grid will contain just four large cells. Next, Example 11-11 presents the source code ofshare.html, followed by brief comments (the code for about.html looks similar).

Example 11-11. The share.html page

<!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 in Figure 11-8 is implemented using a jQuery Mobile multicolumn layout with ui-grid classes (explained in 2).

2

Each of the cells in the grid is styled as 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 Statistics and About pages are split into four sections, which can be laid out in two columns with ui-grid-a. With this two-column layout, each column is allocated 50 percent of the width; with a three-column layout, each column gets about 33 percent, and so forth.

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

Preset grid layouts

Figure 11-24. Preset grid layouts

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

Control groups

Thee Donation page contains a section in which the user can 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 (<input type="radio" name = "amount"). Revisit Chapter 3 to find the complete code in Example 3-5.

jQuery Mobile utilizes the concept of control groups, which are handy for grouping and styling components. The code looks very similar, but now it’s wrapped in the <fieldset> container with data-role="controlgroup", as shown in Example 11-12.

Example 11-12. Grouping components by using <fieldset>

<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 renders this code as shown in Figure 11-25. The buttons are laid out horizontally because of the attribute data-type="horizontal". If you don’t like the default styling of the radio button input fields, feel free to specify the appropriate data-theme either for the entire group or for each input field.

A control group for donation amount

Figure 11-25. A control group for donation amount

Drop-downs and collapsibles

Having the ability to use a minimum amount of screen real estate is especially important in mobile applications. Controls can drop down or pop up a list of information when the user taps a smaller component. Controls that we know as combo boxes or drop-downs in desktop applications look different on mobile devices. The good news is that you don’t need to do any special coding to display a fancy-looking drop-down on the iPhone shown in Figure 11-26. Just use the HTML tag <select>, and the mobile browser will render it with a native look on the user’s device.

The States drop-down in the Donate form

Figure 11-26. The States drop-down 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 might want to create a menu that shows a list of items. First, we’ll show you how to do that by using a pop-up that contains a list view. Example 11-13 is taken from the jQuery Mobile documentation, which suggests implementing a listview inside a pop-up.

Example 11-13. Using <ul> inside the pop-up

<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 like Figure 11-27, which shows an anchor styled as a button.

The Select Donation Amount button before being tapped

Figure 11-27. The Select Donation Amount button before being tapped

After the user taps Select Donation Amount, the menu pops up, as shown in Figure 11-28.

After tapping Select Donation Amount

Figure 11-28. After tapping Select Donation Amount

Example 11-14 demonstrates another way of creating drop-downs by using collapsibles. If the data role of a container is set to be collapsible, the content of the container won’t be initially shown. It will be collapsed, showing only its header with a default icon (the plus sign) until the user taps it.

Example 11-14. Using a collapsible container

<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 test this code in the Ripple emulator, the initial screen will look like Figure 11-29; it’s a <div> with the data-role=collapsible. This code sample also illustrates using different themes for the collapsed and expanded versions 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".

Collapsed view of the Select Donation Amount container

Figure 11-29. Collapsed view of the Select Donation Amount container

After the user taps Select Donation Amount, a menu pops up, as shown in Figure 11-30. The icon on the header changes from a plus sign to a minus sign.

Expanded view of the Select Donation Amount container

Figure 11-30. Expanded view of the Select Donation Amount container

List views

In the previous section, you saw how easy it is to create a nice-looking list (Figure 11-30) by using 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 of the online documentation.

Each list item can contain any HTML element. The media page of the Save The Child application uses listview to arrange videos in the list. Example 11-15 is a code fragment from media.html.

Example 11-15. The listview element with videos

<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 pop-up. The content of each pop-up is located in <div data-role="popup">. The data-rel="popup" in the anchor means that the resource from href has to be opened as a pop-up when the user taps this link.

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

Note that the jQuery Mobile listview (shown in Figure 11-31) is styled in a way that each list item looks like a large rectangle, and the user can tap a list item with a finger without being afraid of touching neighboring controls. There is no such problem with desktop applications because the mouse pointer is much more precise than a finger or even a stylus.

Using listview in media.html

Figure 11-31. Using listview in media.html

NOTE

The <video> tag has the attribute autoplay. But because some mobile users are charged by their phone companies based on their data usage, the application should not automatically start playing video until the user explicitly taps the Play button. There is no such restriction in desktop browsers.

JQUERY MOBILE EVENTS

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

You should be using $(document).on("pageinit") and not $(document).ready(). The former is triggered even for pages loaded as result of Ajax calls, whereas the latter is not. Prior to pageinit, two more events are dispatched: pagebeforecreate and pagecreate. After these two, widget enhancement takes place.

The pagebeforeshow and pageshow events occur 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 programmatic invocation of the changePage() method.

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

Touch events are 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 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 a mobile device changes orientation. This is when jQuery Mobile fires the orientationchange event. The event object will have the property orientation, which will have a value of either portrait or landscape.

There is one event that you can use to set configuration options for 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. You can find more details in the online documentation.

Adding JavaScript

So far we have been able to get by with HTML and CSS only; the jQuery Mobile library is doing its magic, which is helpful for the most part. But we still need a place for JavaScript. The Save The Child application has several hundred 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 logins, donations, maps, and stats. It’s located in the jquerymobile sample project in the file js/app-main.js.

You might also need to write some scripts specific to jQuery Mobile workflows, because in some cases, you might want to override certain behaviors of the library. In these cases, you need to write JavaScript functions to serve as event handlers. For example, jQuery Mobile restricts you from putting more than five buttons on the navbar. But we need six. As you can see in Example 11-16, the footer contains the attribute data-role="navbar", which has the unordered list ul with six <li> items (not shown in the code for brevity).

Example 11-16. The footer with navbar

 <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 navbar, and get ready for a surprise. You’ll see a footer with a two-column and three-row grid, as shown in Figure 11-32, which is a screenshot of a Ripple emulator with an open Chrome Developer Tools panel while inspecting the navbar element in the footer.

Using listview in media.html

Figure 11-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 deploy ui-grid-a, which is a two-column grid (see Grid layouts).

The CSS file app-styles.css (see Project Structure and Navigation) has a provision for giving 16.6 percent of the width for each of six buttons, but we need to programmatically remove ui-grid-a, which jQuery Mobile injected into our code. We’ll do it in JavaScript in the handler for thepagebeforeshow 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 percent of the width will take effect and properly position all six buttons in a row. This is an example of overriding unwanted behavior by using JavaScript. The rest of the code contains familiar functionality from previous sections. We won’t repeat it here, but we will show you some of the code sections that are worth commenting (see Example 11-17).

Example 11-17. Handling navigation in app-main.js

$(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 Login button is located on the header of each page, and it turns into the Logout button when the user logs in. When the user moves from page to page, the old pages are removed from the DOM. To make sure that the login status is properly set, we check that the variable sscLogin in the local storage has the value logged (see 2).

2

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

3

The Donate form code is located in this function. No Ajax calls are 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 the Google Maps API goes here.

While experimenting with the Save The Child application, we created one more version that uses the multipage template, just to get a feeling of how smooth transitioning between pages will be if the entire code base is loaded upfront. Of course, the wait cursor that would otherwise appear between the pages is gone, but the code itself becomes less manageable.

TIP

The Ripple emulator described earlier in this chapter makes it possible for 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 became familiar with a simple-to-use mobile framework. We’ve been using its version 1.3.1, which is 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 (for example, page prefetching breaks images). So be prepared to study the code of this library and to fix 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 begin creating a user interface with jQuery Mobile and where to find more information. Find some time to read the entire online documentation for jQuery Mobile. The learning curve is not steep, but there is a lot to read if you want to become productive with jQuery Mobile.