Skip to content

Latest commit

 

History

History
1346 lines (995 loc) · 81.9 KB

ch3_mockup.asciidoc

File metadata and controls

1346 lines (995 loc) · 81.9 KB

Building Your Application

This book has three parts. In Part 1 we’ll start building Web applications. We’ll be building and re-building a sample application titled Save The Child.

Important
We assume that the readers know how to write programs in JavaScript. If you are not familiar with this language, study the materials from Appendix A first. You’ll find a fast paced introduction to JavaScript there.

In Chapter 1 we’ll start working with a Web designer. We’ll create a mockup, and will start development in pure JavaScript. By the end of this chapter the first version of this application will be working using hard-coded data.

Chapter 2 will show you how to use AJAX techniques to allow Web pages communicate with external data sources without the need to refresh the page. We’ll also cover JSON - a de facto standard data format when it comes to communication between the Web browsers and servers.

Chapter 3 shows how to minimize the amount of manually written JavaScript by introducing popular jQuery library. We’ll rebuild the Save The Child application with jQuery.

After reading of this part you’ll be ready to immerse into a more heavy-duty tools and frameworks that are being used by enterprise developers.

Mocking Up Save The Child Application

Let’s start working on our Web application Save The Child. It’s going to be a Web application that will contain a form for donations to sick children and embeded video player, will integrate with Google maps, will have charts, and more. The goal is to gradually build all the functionality of this Web application while explaining each step of the way and giving you the reasons why we are building it the way we do. By the end of this chapter we’ll have the Web design and the first prototype of the Save The Child.

The proliferation of mobile devices and Web applications require new skills for development of what was known as boring-looking enterprise applications. In the past, design of the user interface of most of the enterprise applications was done by developers to the best of their artistic abilities: a couple of buttons here, and a grid there on a gray background. The business users were happy cause they did not see any better. The application allowed to process business data – what else to wish for? Enterprise business users used to be happy with any UI as long as the application helped them to take care of their business.

But today’s business users are spoiled by nice looking consumer-facing applications, and more often than not new development starts with inviting a Web designer who should create a prototype of the future application. For example, we’ve seen some excellent (from the UI perspective) functional specifications for boring financial applications made by professional designers. Business users slowly but surely becoming more demanding in the area of the UI design solutions. The trend is clear: developer’s art does not cut it anymore.

In enterprise IT shops that work Web applications the Web design is usually done professional Web designer. The software developers are not overly familiar with the tools that Web designers are using. But to make this book useful even for a smaller shops that can’t afford professional Web design, we’ll illustrate the process of design and prototyping of the UI of a Web application.

Our Web designer, let’s call him Jerry, is ready to start working on the mockup (a.k.a. wireframes) - a set of images depicting various views of the future Save The Child application. We expect him to deliver images with comments that would briefly explain what should change in a view if a user will take certain actions, e.g. clicks on the button. You can also think of a UI of an application as a set of states, and the user’s action result in your application transitioning from one state to the other. As nerds and mathematicians say, the UI of your application is a finite state machine", which at any given point of time is in one of the finite number of states, for example, in the view state Donate Form or Auction.

Mobile First?

While starting working on the design of a new Web application keep in mind that most likely some users will access it from mobile devices. Will the proposed UI look good on the mobile devices with smaller screens? Some people suggest using so-called "Mobile First" approach, which means that from the very early stages of Web application development you should do the following:

  • Ensure that your Web application (design and layout) looks on smaller screens

  • Differentiate the content to be shown on large vs small screens (start with small screens and enhance for the larger ones)

  • Test your application on the slow (3G-like) networks and minimize the "weight" of the landing page.

  • Decide on using responsive design (see Chapter 12) vs HTML5 mobile framework vs native vs hybrid (see Chapter 15) approach.

  • If you are planning to use geographical location services decide on the API to be used for mobile devices, but don’t forget about the desktops too.

Note
The users of iOS and Android devices are used to the fact that they can find the closest restaurant or a gas station based on their current location. Do you know that location feature can be available on the desktops too? Google maps API is just one of the services that can find the location of the user’s desktop based on its IP address, Wi-Fi router’s ID or proximity to the cell towers. Zeroing in on your device may not be as precise as with the smartphone’s GPS, but it may be good enough. So why not plan for adding this feature to all versions of your Web application? Finding the closest charity event or a The Child can be done knowing an approximate location of your desktop computer.

Let’s consider pointing devices. At the time of this writing, vast majority of the desktop users work with pixel-perfect mouse pointers or track pads. SmartPhone or tablet users work with fingers. One finger touch can cover a square with 100 pixels. The CNN site shows lots of news links located very close to each other on the screen. A finger may cover more than one link, and Android devices offer you a larger popup allowing you to select the link you really wanted to touch. Having the "Mobile first" state of mind doesn’t mean that CNN would need to keep the larger distance between the links for all the users. But this means that they should foresee the issues or innovate using the features offered by modern mobile devices.

In Chapter 10 we’ll discuss the Responsive Design techniques that allow to create the UI for Web applications that automatically re-allocate the screen content based on the screen size of the user’s device. Although this chapter is about the desktop version of the Save The Child Web application, its screen will consist of several rectangular areas that can be allocated differently (or even hidden) on smartphones or tablets.

Note
Before writing this book we’ve discussed how our application should look/work on mobile devices. But strictly speaking, since the work on multiple chapters was done in parralel, this was not a mobile first approach.
Tip
Consider reading Chapter 12 now to understand what you will need to deal with to developing Web applications that look good on desktop monitors as well as on mobile screens. Understanding of the responsive design principles will help you in communications with your Web designer.

One of the constraints that the mobile users have is the relatively slow speed of the mobile Internet. This means that even though your desktop users will use fast LAN connection lines, your Web application has to be modularized and only the minimal number modules has to be loaded initially. Often mobile providers charge the user based on the amount of consumed data too.

The chances are slim that the desktop users will lose the Internet connection for a long period of time. On the other hand, the mobile users may stay in the area with no or spotty connection. In this case the mobile first thinking can lead to introducing an offline mode with limited functionality.

Thinking upfront of the minimal content to be displayed on a small mobile screens may force you to change the design of the desktop Web pages too. In our sample Save The Child application we need to make sure that there is a space for the Donate button even on the smallest devices.

Introducing Balsamiq Mockups

Visualize a project owner talking to Jerry in a cafeteria, and Jerry is drawing sketches of the future Web site on a napkin. Well, in the 21st Century he’ll use an electronic napkin so to speak - an excellent prototyping tool called Balsamiq Mockups. This easy to use program gives you a working area where you create a mockup of your future Web application by dragging and dropping the required UI components from the toolbar onto the image of the Web page (see The working area of Balsamiq Mockups).

image
Figure 1. The working area of Balsamiq Mockups

If you can’t find the required image in Balsamiq’s library, add your own by dragging and dropping it onto the top toolbar. For example, the mockup in Chapter 10 uses our images of the iPhone that we’ve added to Balsamiq assets.

Tip
If you prefer using free tools, consider using Mockflow.

When the prototype is done, it can be saved as an image and sent to the project owner. Another option is to export the Balsamiq project into XML, and if both the project owner and Web designer have Balsamiq installed, they can work on the prototype in collaboration. For example, the designer exports the current states of the project, the owner imports it and makes corrections or comments, then exports it again and sends it back to the designer.

The Project Owner Talks to a Web Designer

During the first meeting Jerry talks to the project owner discussing the required functionality and then creates the UI to be implemented by Web developers. The artifacts produced by the designer vary depending on the qualifications of the designer. This can be a set of images representing different states of the UI with little callouts explaining the navigation of the application. If the Web designer is familiar with HTML and CSS, developers may get a working prototype in the form of HTML and CSS files, and this is exactly what Jerry will create by the end of this chapter.

Our project owner said to Jerry: "The Save The Child Web application should allow people to make donations to The Children. The users should be able to find these children by specifying a geographical area on the map. The application should include a video player and display statistics about the donors and recipients. The application should include an online auction with proceeds going to charity. We’ll start working on the desktop version of this Web first, but your future mockup should include three versions of the UI supporting desktops, tablets, and smartphones".

After the meeting Jerry launched Balsamiq and started to work. He decided that the main window will consist of four areas laid out vertically:

  1. The header with the logo and several navigation buttons

  2. The main area with the Donate support plus the video player

  3. The area with the Find Local Kid, statistics, and charts.

  4. The footer with several house-holding links plus the icons for Twitter and FaceBook.

First Mockups

The first deliverable of our Web designer (see The main view before clicking Donate Now and The main view after clicking Donate Now) depicted two states of the UI: before and after clicking the button Donate Now. The Web designer suggested that on the button click the Video Player would turn into a small button revealing the donation form.

fig 03 02
Figure 2. The main view before clicking Donate Now
fig 03 03
Figure 3. The main view after clicking Donate Now

The project owner suggested that turning the video into a Donate button may not be a the best idea. We shouldn’t forget that the main goal of this application is collecting donation, so they decided to keep the user’s attention on the Donate area and move the video player to the lower portion of the window.

After that they went over the mockups of the authorization routine. The view states in this process can be : 1. Not Logged On 2. The Login Form 3. Wrong ID/Password 4. Forgot Password 5. Successfully Logged On

The Web designer has created mockups of some of these states as shown on The user haven’t clicked on the Login button and The user haven’t clicked on the Login button.

fig 03 04
Figure 4. The user haven’t clicked on the Login button

The latter shows different UI states should the user decide to log in. The project owner reviewed the mockups and return them back to Jerry with some comments. The project owner wanted to make sure that the user doesn’t have to log on to the application to access the Web site. The process of making donations has to be as easy as possible, and forcing the donor to log on may scare some people away, so the project owner left his comment as shown on The user haven’t clicked on the Login button.

fig 03 05
Figure 5. The user haven’t clicked on the Login button

This is enough of a design for us to build a working prototype of the app and start getting the feedback from business users. In the real world when a prospective client (including business users from your enterprise) approaches you asking for a project estimate, provide them with the document with a detailed work breakdown and the screenshops made by Balsamiq or a similar tool.

From Mockups to a Prototype

We are lucky - Jerry knows HTML and CSS. He’s ready to turn the still mockups into the first working prototype. It’ll use only hard-coded data but the layout of the site will be done in CSS and we’ll use HTML5 markup. We’ll design this application as a Single-Page Application (SPA).

Single Page Applications

A Single Page Web Application (SPA) is an architectural approach that doesn’t require the user going through multiple pages to navigate the site. The user enters the URL in the browser, which brings the Web page that remains open on the screen until the user stop working with this application. The portion of the user’s screen may change as the user navigate the application, the new data comes in using the AJAX techniques (see Chapter 2), or the new DOM elements will need to be created during the runtime, but the main page itself doesn’t gets reloaded. This allows building so-called fat client applications that can remember its state. Besides, most likely your HTML5 application will use some JavaScript framework, which in SPA gets loaded only once when the home page gets created by the browser.

Have you ever seen a monitor of a trader working for a Wall Street firm? They usually have three or four large monitors, but let’s just look at one of them. Imagine a busy screen with lots and lots constantly changing data grouped in dedicated areas of the window. This screen shows the constantly changing prices from financial markets, the trader can place orders to buy or sell products, and notifications on completed trades are also coming to the same screen. If this is would be a Web application it would live in the same Web page. No menus to open another windows.

The price of Apple share was $590.45 just a second ago and now it’s $590.60. How can this be done technically? Here’s one of the possibilities: every second an AJAX is being made to the remote server providing current stock prices and the JavaScript code finds in the DOM the HTML element responsible for rendering the price and then modifies its value with the latest price.

Have you seen a Web page showing an input box of Google’s Gmail? It looks like a table with a list of rows representing the sender, subject, and the date of when each email arrived. All of a sudden you see a new row in bold on top of the list - the new email came in. How was this done technically? A new object(s) was created and inserted into a DOM tree. No page changes, no needs for the user to refresh the browser’s page - an undercover AJAX call gets the data and JavaScript changes the DOM. The content of DOM changed - the user sees an updated value.

Running Code Examples from WebStorm

The authors of this book use WebStorm IDE 7 from JetBrains for developing real-world projects. Appendix C explains how to run code samples in WebStorm.

This chapter will include lots of code samples illustrating how the UI is gradually being built. We’ve created a number small Web applications. Each of them can be run independently. Just download and open in WebStorm (or any other) IDE the directory containing samples from Chapter 1. After that you’ll be able to run each of these examples by right-clicking on the index.html and selecting Open in Browser menu of WebStorm.

Note
We assume that the users of our Save The Child application work with the modern versions of Web browsers (two year old or younger). The real world Web developers need to deal with finding workarounds to the unsupported CSS or HTML5 features in the old browsers, but modern IDE generate HTML5 boilerplate code that include large CSS files providing different solutions to older browsers.

JavaScript frameworks implement workaround for features unsupported by old browsers too, so we don’t want to clutter the text providing several versions of the code just to make book samples work in outdated browsers. This is especially important when developing Enterprise apps in situations where the majority of users are locked in a particular version of and older Web browser.

Our First Prototype

In this section you’ll see several projects that show how the static mockup will turn into a working prototype with the help of HTML, CSS, and JavaScript. Jerry, the designer, decided to have four separate areas on the page hence he created the HTML file index.html that has the tag <header> with the navigation tag <nav>, two <div> tags for the middle sections of the page and a <footer>:

<!DOCTYPE html>
<html lang="en">
 <head>
	<meta charset="utf-8">
	<title>Save The Child | Home Page</title>
	<link rel="stylesheet" href="css/styles.css">
 </head>
 <body>
	<div id="main-container">
		<header>
		 <h1>Save The Child</h1>
		 <nav>
		  <ul>
			<li>
			  <a href="javascript:void(0)">Who we are</a>
			</li>
			<li>
			  <a href="javascript:void(0)">What we do</a>
			</li>
			<li>
			  <a href="javascript:void(0)">Way to give</a>
			</li>
			<li>
			  <a href="javascript:void(0)">How we work</a>
			</li>
		  </ul>
		 </nav>
		</header>
		<div id="main" role="main">
			<section>
			  Donate section and Video Player go here
			</section>
			<section>
			  Locate The Child, stats and tab folder go here
			</section>
		</div>
		<footer>
			<section id="temp-project-name-container">
				<b>project 01</b>: This is the page footer
			</section>
		</footer>
	</div>
 </body>
</html>

Note that the above HTML file includes the CSS file shown below using the <link> tag. Since there is no content yet for the navigation links to open, we use the syntax href="javascript:void(0) that allows to create a live link that doesn’t load any page, which is fine on the prototyping stage.

Tip
If reusability is very important for you, avoid using overly specific selectors like id="temp-project-name-container" (or even ID selectors) as they limit reusability.
/* Navigation menu */
nav {
	float: right
}
nav ul li {
	list-style: none;
	float: left;
}
nav ul li a {
	display: block;
	padding: 7px 12px;
}

/* Main content
 #main-container is a wrapper for all page content
 */
#main-container {
	width: 980px;
	margin: 0 auto;
}
div#main {
	clear: both;
}

/* Footer */
footer {
	/* Set background color just to make the footer standout*/
	background: #eee;
	height: 20px;
}
footer #temp-project-name-container {
	float: left;
}

The above CSS controls not only the styles of the page content, but also that sets the page layout. The <nav> section should be pushed to the right. If an unordered list is placed inside the <nav>, it should be left aligned. The width of the HTML container with ID main-container should be 980 pixels, and it has to be automatically centered. The footer will be 20 pixels high and should have a gray background. The first version of our Web page is shown on Working prototype. Take 1: Getting Started. Run index.html from the project-01-get-started.

Tip
In Chapter 10 you’ll see how to create Web pages with more flexible layouts that don’t require specifying absolute sizes in pixels.
fig 03 06
Figure 6. Working prototype. Take 1: Getting Started

The next version of our prototype is more interesting, and it will contain a lot more code. First of all, the CSS file will become fancier, the layout of the four page sections will properly divide the screen real estate. We’ll add a Logo and a nicely styled Login button to the top of the page. This version of the code will also introduce some JavaScript supporting user’s authorization. Run the project-02-login, and you’ll see a window similar to Working prototype. Take2: Login.

fig 03 07
Figure 7. Working prototype. Take2: Login

This project has several directories to keep JavaScript, images, CSS, and fonts separately. We’ll talk about special icon fonts later in this section, but first things first - let’s take a close look at the HTML code.

<!DOCTYPE html>
<html lang="en">
 <head>
 	<meta charset="utf-8">
 	<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
 	<title>Save The Child</title>
 	<link rel="stylesheet" href="assets/css/styles.css">

 </head>
  <body>
 	<div id="main-container">
 	 <header>

 	  <h1 id="logo"><a href="javascript:void(0)">Save The Child</a></h1>

 	   <nav id="top-nav">
 	  	<ul>
 	  	  <li id="login">
 	  	   <div id="authorized">
 	  	    <span class="icon-user authorized-icon"></span>
 	  	    <span id="user-authorized">admin</span>
 	  	    <br/>
 	  	    <a id="profile-link" href="javascript:void(0);">profile</a> |
 	  	    <a id="logout-link" href="javascript:void(0);">logout</a>
 	  	   </div>

 	  	   <form id="login-form">
 	  	    <span class="icon-user login-form-icons"></span>
 	  	    <input id="username" name="username" type="text"
 	  	                placeholder="username" autocomplete="off" />
 	  	    &nbsp; <span class="icon-locked login-form-icons"></span>
 	  	    <input id="password" name="password"
 	  	                type="password" placeholder="password"/>
 	  	   </form>
 	  	   <a id="login-submit" href="javascript:void(0)">login &nbsp;
 	  	 	        <span class="icon-enter"></span> </a>

			<div id="login-link" class="show-form">login
			              &nbsp; <span class="icon-enter"></span></div>

 	  	 	<div class="clearfix"></div>
 	  	 </li>
 	  	 <li id="top-menu-items">
 	  	 	<ul>
 	  	 		<li>
 	  	 			<a href="javascript:void(0)">Who We Are</a>
 	  	 		</li>
 	  	 		<li>
 	  	 			<a href="javascript:void(0)">What We Do</a>
 	  	 		</li>
 	  	 		<li>
 	  	 			<a href="javascript:void(0)">Where We Work</a>
 	  	 		</li>
 	  	 		<li>
 	  	 			<a href="javascript:void(0)">Way To Give</a>
 	  	 		</li>
 	  	 	</ul>
 	  	 </li>
 	  	</ul>
 	   </nav>
 	 </header>

 	 <div id="main" role="main">
 	 	<section id="main-top-section">
 	 		<br/>
 	 		Main content. Top section.
 	 	</section>
 	 	<section id="main-bottom-section">
 	 		Main content. Bottom section.
 	 	</section>
 	 </div>
 	 <footer>
 	 	<section id="temp-project-name-container">
 	 		<b>This is the footer</b>
 	 	</section>
 	 </footer>
 	</div>
 	<script src="assets/js/main.js"></script>
 </body>
</html>

Usually, the logos on multi-page Web sites are clickable - they bring up the home page. That’s why Jerry placed the anchor tag in the logo section. But we are planning to build a single-page application so having a clickable logo won’t be needed.

Run this project in WebStorm and click on the button Login, and you’ll see that it reacts. But looking at the login-related <a> tags in the <header> section you’ll find nothing but href="javascript:void(0)". So why the button reacts? Read the code in the main.js shown below, and you’ll find there line loginLink.addEventListener('click', showLoginForm, false); that invokes the callback showLoginForm(). That why the Login button reacts. This seems confusing cause the anchor component was used here just for styling purposes. In this example a better solution would be to replace the anchor tag <a id="login-link" class="show-form" href="javascript:void(0)"> with another component that doesn’t make the code confusing, for example <div id="login-link" class="show-form">.

Important
We do not want to build Web applications the old way when a server-side program prepares and sends UI fragments to the client. The server and the client send to each other only the data. If the server is not available, we can use the local storage (the offline mode) or a mockup data one the client.

Our Main Page JavaScript

Now let’s examine the JavaScript code located in main.js. This code will self-invoke the anonymous function, which creates an object - encapsulated namespace ssc (short for Save Sick Child). This avoids polluting the global namespace. If we wanted to expose anything from this closure to the global namespace we could have done this via the variable ssc as described in Appenix A in section Closures.

// global namespace ssc
var ssc = (function() {
    // Encapsulated variables

    // Find login section elements                   //  (1)
	var loginLink = document.getElementById("login-link");
	var loginForm = document.getElementById("login-form");
	var loginSubmit = document.getElementById('login-submit');
	var logoutLink = document.getElementById('logout-link');
	var profileLink = document.getElementById('profile-link');
	var authorizedSection = document.getElementById("authorized");

	var userName = document.getElementById('username');
	var userPassword = document.getElementById('password');

	// Register event listeners                       // (2)

	loginLink.addEventListener('click', showLoginForm, false);
	loginSubmit.addEventListener('click', logIn, false);
	logoutLink.addEventListener('click', logOut, false);
	profileLink.addEventListener('click', getProfile, false);

	function showLoginForm() {
		loginLink.style.display = "none";             // (3)
		loginForm.style.display = "block";
		loginSubmit.style.display = "block";
	}

	function showAuthorizedSection() {
		authorizedSection.style.display = "block";
		loginForm.style.display = "none";
		loginSubmit.style.display = "none";
	}

	function logIn() {
		//check credentials
		var userNameValue = userName.value;
		var userNameValueLength = userName.value.length;
		var userPasswordValue = userPassword.value;
		var userPasswordLength = userPassword.value.length;

		if (userNameValueLength == 0 || userPasswordLength == 0) {
			if (userNameValueLength == 0) {
				console.log("username can't be empty");
			}
			if (userPasswordLength == 0) {
				console.log("password can't be empty");
			}
		} else if (userNameValue != 'admin' ||
		                          userPasswordValue != '1234') {
			console.log('username or password is invalid');

		} else if (userNameValue == 'admin' &&
		                          userPasswordValue == '1234') {

			showAuthorizedSection();                     // (4)
		}
	}

	function logOut() {
		userName.value = '';
		userPassword.value = '';
		authorizedSection.style.display = "none";
		loginLink.style.display = "block";
	}

	function getProfile() {
		console.log('Profile link clicked');
	}

})();
  1. First query the DOM to get references to login-related HTML elements.

  2. Register event listeners for the clickable login elements.

  3. To make a DOM element invisible set its style.display="none". Hide the login button and show the login form having two input fields for entering the user id and the password.

  4. If the user is admin and the password is 1234, hide the loginForm and make the top corner of the page look as in After successful login.

Warning
We keep the user ID and password in this code just for the illustration purposes. Never do this in your applications. Authentication has to be done in a secure way on the server side.
fig 03 08
Figure 8. After successful login
Where to put JavaScript

We recommend placing the <script> tag with your JavaScript at the end of your HTML file as in our index.html above. If you move the line <script src="js/main.js"></script> to the top of the <body> section and re-run index.html the screen will look as in Working prototype. Take2: Login, but clicking on the Login won’t display the login form as it should. Why? Because registering of the event listeners in the script main.js failed cause the DOM components (login-link, login-form and others) were not created yet by the time this script was running. Open the Firebug, Chrome Developer Tools, or any other debugging tool and you’ll see an error on the console that will look similar to the following:

"TypeError: loginLink is null loginLink.addEventListener('click', showLoginForm, false);"

Of course, in many cases your JavaScript code could have tested if the DOM elements exist before using them, but in this particular sample it’s just easier to to put the script at the end of the HTML file. Another solution would be to load the JavaScript code located in main.js in a separate handler function that would run only when the window’s load event is dispatched by the browser indicated that the DOM is ready: window.onload = function() {…​}. You’ll see how to do this in the next version of main.js.

Tip
The <script> tag support defer and async attributes that allow to execute external JavaScript files after the parsing of a Web page is complete.
The CSS of our Main Page

After reviewing the HTML and JavaScript code let’s spend a little more time with the CSS that supports the pages shown in Working prototype. Take2: Login. The difference between the screen shots shown in Working prototype. Take 1: Getting Started and Working prototype. Take2: Login is substantial. First, the top left image is nowere to be found in index.html. Open the styles.css file and you’ll see the line background: url(../img/logo.png) no-repeat; in the header h1#logo section.

The page layout is also specified in the file styles.css. In this version the sizes of each section is specified in pixels (px), which won’t make you page fluid and easily resizable. For example, the HTML element with id="main-top-section" is styled like this:

#main-top-section {
	width: 100%;
	height: 320px;
	margin-top: 18px;
}

Jerry styled the main to section to take the entire width of the browser’s window and to be 320 pixels tall. If you’ll keep in mind the "Mobile First" mantra, this may not be the best approach cause 320 pixels mean difference size (in inches) on the displays with different screen density. For example, 320 pixels on the iPhone 5 with retina display will look a lot smaller than 320 pixels on the iPhone 4. You may consider switching from px to em units: 1em is equal to the current font height, 2em means twice the size et al. You can read more about creating scalable style sheets with em units at http://www.w3.org/WAI/GL/css2em.htm.

What looks a Login button on Working prototype. Take2: Login is not a button, but a styled div element. Initially it was a clickable anchor <a>, and we’ve explained this change right after the listing shown index.html above. The CSS fragment supporting the Login button looks like this:

li#login input {
	width: 122px;
	padding: 4px;
	border: 1px solid #ddd;
	border-radius: 2px;
	-moz-border-radius: 2px;
	-webkit-border-radius: 2px;
}

The border-radius element makes the corners rounded of the HTML element it applied to. But why we repeat it three times with additional prefixes -moz- and -webkit-? These are so called CSS vendor prefixes, which allow the Web browser vendors to implement experimental CSS properties that haven’t been standardized yet. For example, -webkit- is the prefix for all WebKit-based browsers: Chrome, Safari, Android, iOS. Microsoft uses -ms- for Internet Explorer, Opera uses -o-. These prefixes are temporary measures, which make the CSS files heavier than they need to be. The time will come when the CSS3 standard properties will be implemented by all browser vendors and you won’t need to use these prefixes.

As a matter of fact, unless yo uwant this code to work in the very old versions of Firefox, you can remove the line -moz-border-radius: 2px; from our styles.css because Mozilla has implemented the property border-radius in most of their browser . You can find a list of CSS properties with the corresponding vendor prefixes in this list maintained by Peter Beverloo.

The footer section comes next. Run the project called project-03-footer and you’ll see a new version of the Save The Child page with the bottom portion that looks as in The footer section. The footer section shows several icons linking to Facebook, Google Plus, Twitter, RSS feed, and e-mail.

fig 03 09
Figure 9. The footer section

The HTML section of our first prototype is shown below. At this point it has a number of <a> tags, which have the dummy references href="javascript:void(0)" that don’t redirect the user to any of these social sites.

<footer>
 <section id="temp-project-name-container">
	<b>project 03</b>: Footer Section | Using Icon Fonts
 </section>
 <section id="social-icons">
	<a href="javascript:void(0)" title="Our Facebook page">
	   <span aria-hidden="true" class="icon-facebook"></span></a>
	<a href="javascript:void(0)" title="Our Google Plus page">
	   <span aria-hidden="true" class="icon-gplus"></span></a>
	<a href="javascript:void(0)" title="Our Twitter">
	   <span aria-hidden="true" class="icon-twitter"></span></a> &nbsp;
	<a href="javascript:void(0)" title="RSS feed">
	   <span aria-hidden="true" class="icon-feed"></span></a>
	<a href="javascript:void(0)" title="Email us">
	   <span aria-hidden="true" class="icon-mail"></span></a>
 </section>
</footer>

Each of the above anchors is styled using vector graphics icon fonts that we’ve selected and downloaded from http://icomoon.io/app. Vector graphics images are being re-drawn using vectors (strokes) as opposed to raster graphics, which is are pre-drawn in certain resolution images. The raster graphics can give you these boxy pixelated images if the size of the image needs to be increased. We use the vector images for our footer section that are treated as fonts. They will look as good as originals on any screen size, besides you can change their properties (e.g. color) as easy as you’d do with any other font. The images that you see on The footer section are are located in the fonts directory of the project-03-footer. The IcoMoon web application will generate the fonts for you based on your selection and you’ll get a sample html file, fonts, and CSS to be used with your application. Our icon fonts section in styles.css will look as follows:

/* Icon Fonts */
@font-face {
	font-family: 'icomoon';
	src:url('../fonts/icomoon.eot');
	src:url('../fonts/icomoon.eot?#iefix') format('embedded-opentype'),
		url('../fonts/icomoon.svg#icomoon') format('svg'),
		url('../fonts/icomoon.woff') format('woff'),
		url('../fonts/icomoon.ttf') format('truetype');
	font-weight: normal;
	font-style: normal;
}

The Donate Section

The section with the Donate button and the donation form will be located in the top portion of page right below the navigation area. Initially, the page will open up with the background image of a sick but smiley boy on the right and a large Donate button on the left. The image shown on The initial view of the Donate section is taken from a large collection of photos at iStockphoto Web site. We’re also using two more background images here: one with the flowers, and the other with the sun and clouds, and you can find the references to these images in the styles.css file. Run the project-04-donation and you’ll see the new version of or Save The Child page that will look as on The initial view of the Donate section.

fig 03 10
Figure 10. The initial view of the Donate section

Lorem Ipsum is a dummy text widely used in printing, typesetting, and Web design. It’s used as a placeholder to indicate the text areas that should be filled with a real content later on. You can read about it at http://www.lipsum.com. This is how the HTML fragment supporting The initial view of the Donate section looks like (no CSS is shown for brevity).

<div id="donation-address">
	<p class="donation-address">
		Lorem ipsum dolor sit amet, consectetur e magna aliqua.
		Nostrud exercitation ullamco laboris nisi ut aliquip ex
		ea commodo consequat.
		Duis aute irure dolor in reprehenderit in voluptate velit
		esse cillum dolore eu fugiat nulla pariatur.
		Excepteur sint occaecat cupidatat non proident.
	</p>
	<button class="donate-button" id="donate-button">
		<span class="donate-button-header">Donate Now</span>
		<br/>
		<span class="donate-2nd-line">Children can't wait</span>
	</button>

</div>

Clicking the button Donate should reveal the form where the user should be able to enter her name, address and the donation amount. Instead of opening a popup window we’ll just change the content on the left revealing the form, and move the button Donate to the right. After clicking on Donate button shows how the top portion of our page will look like after the user clicks the Donate button.

fig 03 11
Figure 11. After clicking on Donate button

The HTML of the donation form shown on After clicking on Donate button is shown below. When the user clicks on the Donate button the content of the form should be sent to PayPal or any other payment processing system.

<div id="donate-form-container">
 <h3>Make a donation today</h3>
 <form name="_xclick" action="https://www.paypal.com/cgi-bin/webscr" method="post">
  <div class="donation-form-section">
	<label class="donation-heading">Please select or enter
		<br/> donation amount</label>
	<input type="radio" name = "amount" id= "d10" value = "10"/>
	<label for = "d10">10</label>
	<br/>
	<input type="radio" name = "amount" id = "d20" value="20" />
	<label for = "d20">20</label>
	<br/>
	<input type="radio" name = "amount" id="d50" checked="checked" value="50" />
	<label for="d50">50</label>
	<br/>
	<input type="radio" name = "amount" id="d100" value="100" />
	<label for="d100">100</label>
	<br/>
	<input type="radio" name = "amount" id="d200" value="200" />
	<label for="d200">200</label>
	<label class="donation-heading">Other amount</label>
	<input id="customAmount" name="amount" value=""
	       type="text"  autocomplete="off" />
  </div>
  <div class="donation-form-section">
	<label class="donation-heading">Donor information</label>
	<input type="text" id="full_name" name="full_name"
	       placeholder="full name *" required>
	<input type="email" id="email_addr" name="email_addr"
	       placeholder="email *" required>
	<input type="text" id="street_address" name="street_address"
	       placeholder="address">
	<input type="text" id="city" name="scty" placeholder="city">
	<input type="text" id="zip" name="zip" placeholder="zip/postal code">
	<select name="state">
		<option value="" selected="selected"> - State - </option>
		<option value="AL">Alabama</option>
		<option value="WY">Wyoming</option>
	</select>
	<select name="country">
		<option value="" selected="selected"> - Country - </option>
		<option value="United States">United States</option>
		<option value="Zimbabwe">Zimbabwe</option>
	</select>
  </div>

  <div class="donation-form-section make-payment">
	<h4>We accept Paypal payments</h4>
	<p>
		Your payment will processed securely by <b>PayPal</b>.
		PayPal employ industry-leading encryption and fraud prevention tools.
		Your financial information is never divulged to us.
	</p>

	<button  type="submit" class="donate-button donate-button-submit">
		<span class="donate-button-header">Donate Now</span>
		<br/>
		<span class="donate-2nd-line">Children can't wait</span>
	</button>
	<a id="donate-later-link" href="javascript:void(0);">I'll donate later
	<span class="icon-cancel"></span></a>
  </div>
 </form>
</div>

The JavaScript code supporting the UI transformations related to the button Donate is shown below. It’s the code snippet from the main.js from project-04-donation. The click on the Donate button invokes the event handler showDonationForm(), which simply hides the <div id="donation-address"> with Lorem Ipsum and displays the donation form: ` <form name="_xclick" action="https://www.paypal.com/cgi-bin/webscr" method="post">">`. When the form field loses focus or after the user clicked on the Submit button, the data from the form _xclick must be validated and sent to paypal.com. If the user clicks on "I’ll donate later", the code hides the form and shows the Lorem Ipsum from the <div id="donation-address"> again.

Important
Not including proper form validation is a sign of a rookie developer. This can easily irritate users. Instead of showing error messages like "Please include only numbers in the phone number field" use regular expressions to programmatically strip non-digits away.

Two select dropdowns in the code above contain hard-coded values of all states and countries. For brevity, we’ve listed just a couple of entries in each. In Chapter 2 we’ll populate these dropdowns using the external data in JSON format.

Tip
Don’t show all the countries in the dropdown unless your application is global. If the majority of the users of your country live in France, display on top of the list France and not Afghanistan (the first country in alphabetical order).
Assigning Function Handlers. Take 1.

The next code fragment is an extract of JavaScript file main.js provide by Jerry. This code contains function handlers that process user clicks in the Donate section.

(function() {
	var donateBotton = document.getElementById('donate-button');
	var donationAddress = document.getElementById('donation-address');
	var customAmount = document.getElementById('customAmount');
	var donateForm = document.forms['_xclick'];
	var donateLaterLink = document.getElementById('donate-later-link');
	var checkedInd = 2;

	function showDonationForm() {
		donationAddress.style.display = "none";
		donateFormContainer.style.display = "block";
	}

    // Register the event listeners
	donateBotton.addEventListener('click', showDonationForm, false);
	customAmount.addEventListener('focus', onCustomAmountFocus, false);
	donateLaterLink.addEventListener('click', donateLater, false);
	customAmount.addEventListener('blur', onCustomAmountBlur, false);

	// Uncheck selected radio buttons if the custom amount was chosen
	function onCustomAmountFocus() {
		for (var i = 0; i < donateForm.length; i++) {
			if (donateForm[i].type == 'radio') {
				donateForm[i].onclick = function() {
					customAmount.value = '';
				}
			}
			if (donateForm[i].type == 'radio' && donateForm[i].checked) {
				checkedInd = i;
				donateForm[i].checked = false;
			}
		}
	}

	function onCustomAmountBlur() {
		var value = customAmount.value;
		if (value == '') {
		    // The user haven't entered other amount
			donateForm[checkedInd].checked = true;
		}
	}

	function donateLater(){
		donationAddress.style.display = "block";
		donateFormContainer.style.display = "none";
	}

})();

The code above contains an example of an inefficient code that in a loop assigns a click event handler to each radio button should the user click any radio button after visiting the Other Amount field. This was a Jerry’s understanding of how to reset the value of the customAmount variable. Jerry was not familiar with the capture phase of the events that can intercept the click event on the radio buttons container’s level and simply reset the value of customAmount regardless of which specific radio button is clicked.

Assigning Function Handlers. Take 2.

Let’s improve the code from the previous section. The idea is to intercept the click event during the capture phase (see the DOM Events section in ,Appendix A) and if the Event.target is any radio button, perform customAmount.value = '';

var donateFormContainer = document.getElementById('donate-form-container');

// Intercept any click on the donate form in a capturing phase
donateFormContainer.addEventListener("click", resetCustomAmount, true);
function resetCustomAmount(event){

    // reset the customAmount
	if (event.target.type=="radio"){
		customAmount.value = '';
	}
}

The code of the onCustomAmountFocus() doesn’t need to assign function handlers to the radio buttons any longer:

function onCustomAmountFocus() {
	for (var i = 0; i < donateForm.length; i++) {
		if (donateForm[i].type == 'radio' && donateForm[i].checked) {
			checkedInd = i;
			donateForm[i].checked = false;
		}
	}
}

In the Donate section we started working with event handlers. You’ll see many more examples of event processing throughout the book.

Adding Video

In this section we’ll add a video player to our Save The Child application. The goal is to play a short animation encouraging kids to fight the disease. We’ve hired a professional animation artist Yuri who has started working on the animation. Meanwhile let’s take care of embedding the video player showing any sample video file.

Adding the HTML5 Video Element

Let’s run the project called project-05-html5-video to see the video playing, and after that we’ll review the code. The new version of the Sick The Child app should look as in The video player is embeded. The users will see an embedded video player on the right that can play the video located in the assets/media folder of the project project-05-html5-video.

fig 03 12
Figure 12. The video player is embeded

Let’s see how our index.html has changed since its previous version. The bottom part of the main section includes the <video> tag. In the past, the videos in Web pages were played predominantly by the browser’s Flash Player plugin (even older popular plugins included RealPlayer, MediaPlayer, and QuickTime). For example, you could have used the HTML tag `<embed src="myvideo.swf" height="300" width="300">`and if the user’s browser supports Flash Player, that’s all you needed for basic video play. While there were plenty of open source video players, creation of the enterprise-grade video player for Flash videos became an important skill for some software developers. For example, HBO, an American cable network offers an advanced multi-featured video player embedded into www.hbogo.com for their subscribers.

In today’s world most of the modern mobile Web browsers don’t support Flash Player, and the video content providers prefer broadcasting videos in formats that are supported by all the browsers and can be embedded into Web page using the standard HTML5 element <video> (see its current working draft is published at http://www.w3.org/wiki/HTML/Elements/video.

The following code fragment illustrates how we’ve embedded the video into the bottom portion of our Web page (index.html). It includes two <source> elements, which allows to provide alternative media resources. If the Web browser supports playing video specified in the first <source> element, it’ll ignore the other versions of the media. For example, the code below offers two versions of the video file: intro.mp4 (in H.264/MPEG-4 format natively supported by Safari and Internet Explorer) and intro.webm (WebM format for Firefox, Chrome, and Opera).

<section id="main-bottom-section">
 <div id="video-container">
 	<video controls poster="assets/media/intro.jpg"
 	       width="390px" height="240" 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 video</p>
 	</video>

 		<h3>Video header goes here</h3>
 		<h5><a href="javascript:void(0);">More videos</a></h5>
 </div>
</section>

The boolean property controls asks the Web browser to display the video player with controls (the play/pause buttons, the full screen mode, et al.) If you wouldn’t use the property controls your JavaScript could would have to control the playback. The poster property of the <video> tag specifies the image to display as a placeholder for the video - this is the image you see on The video player is embeded. In our case the preload valus is metadata, which means that we want the Web browser to preload just the first frame of the video its metadata. Should we used preload="auto", the video would start loading in the background as soon as the Web page was loaded unless the user’s browser doesn’t allow it (e.g. Safari on iOS) for saving the bandwidth.

All major Web browsers released in 2011 and later include their own embedded video players that support the <video> element. It’s great that your code doesn’t depend on the support of the Flash Player, but now video players look different depending on which browser the user has.

If neither .mp4 nor .webm files can be played, the content in the <p> tag displays the fallback message "Sorry, your browser doesn’t support video". If you need to support older Web browsers that don’t support HTML5 video, but support Flash Player, you can replace this <p> tag with the <object> and <embed> tags that embed another media file that Flash Player understands. Finally, if you believe that some users may have the browsers that support neither the <video> tag nor Flash Player, just add the links to the files listed in the <source> tags right after the closing </video> tag.

Embedding YouTube Videos

Another way to include videos in your Web application is by uploading them to YouTube first and then embedding if into your Web page. This provides a number of benefits:

  • The videos are hosted on Google’s servers and use their bandwidth.

  • The users can either watch the video as a part of your application’s Web page or, by clicking on the YouTube logo on the status bar of the video player you can continue watching the video from its original YouTube URL.

  • YouTube is streaming videos in the compressed form and the user can watch it as the bytes come in - it doesn’t require a video to be fully preloaded to the user’s device.

  • YouTube stores videos in several formats and automatically selects the best one based on the user’s Web browser (user agent).

  • The HTML code to embed a YouTube video is generated for you by pressing the Share and then Embed link by the video itself.

  • You can enrich your Web application by incorporating extensive video libraries by using the YouTube Data API. You can create fine tuned searches retrieving channels, playlists, videos, manage subscriptions, and authorize user requests.

  • Your users can save the YouTube videos on their local drive using free Web Browsers add-ons like DownloadHelper extension for Firefox or a RealDownloader.

Tip
Youtube offers an Opt-In Trial of HTML5 video, which allows the users to request playing most of the videos using HTML 5 video (even those recorded for Flash Player).

Embedding a YouTube video into your HTML page is simple. Find the page with the video on YouTube and press the links Share and Embed located right under the video. Then select the size of your video player and HTTPS encryption if needed (see Chapter 9 on Web security for reasoning). When this is done, copy the generated iFrame section into your page.

Open the file index.html in the project-06-YouTube-video and you’ll see there a code that replaces the <video> tag of the previous project. It should look like this:

<section id="main-bottom-section">
 <div id="video-container">
  <div id="video-container">
  	<iframe src="http://www.youtube.com/embed/VGZcerOhCuo?wmode=transparent&hd=1&vq=hd720"
  	        frameborder="0" width="390" height="240"></iframe>

  	<h3>Video header goes here</h3>
  	<h5><a href="javascript:void(0);">More videos</a></h5>
  </div>
 </div>
</section>

Note that the initial size of our video player is 390x240 pixels. The <iframe> wraps the URL of the video, which in this example ends with parameters hd=1 and vq=hd720. This is how you can force YouTube to load video in HD quality. Run the project-06-YouTube-video and if shows you a Web page that looks as in The YouTube player is embeded.

fig 03 13
Figure 13. The YouTube player is embeded

Now let’s do yet another experiment. Enter the URL of our video directly in your Web browser, turn on the Firegug or Developer Tools. We did it in Firebug under Mac OS and selected the Net tab. Then HTML Response looked as in HTTP Response object from YouTube. YouTube recognized that this Web browser is capable of playing Flash content (FLASH_UPGRADE) and picked the QuickTime as a fallback (QUICKTIME_FALLBACK).

fig 03 14
Figure 14. HTTP Response object from YouTube

Our brief introduction to embedding videos in HTML is over. Let' keep adding new features to the Save The Child Web application. This time we’ll get familiar with the HTML5 Geolocation API.

Adding Geolocation Support

HTML5 includes the Geolocation API that allows programmatically figure out the latitude and longitude of the user’s device. Most of the people are accustomed to the non-Web GPS applications in cars or mobile devices that display maps and calculate distances based on the current coordinates of the user’s device or motor vehicle. But why do we need the Geolocation API in a desktop Web application?

The goal of this section is to demonstrate a very practical feature - finding registered The Children based on the user’s location. This way the users of the Save The Child can find the needy children in a particular geographical area. In this chapter you’ll just learn the basics of HTML5 GeoLocation API, but we’ll continue improving the location feature of the Save The Child in the next chapter.

Tip
The World Wide Web Consortium has published proposed recommendation of the Geolocation API Specification.

Does your old desktop computer have a GPS hardware? Most likely it doesn’t. But its location can be calculated with varying degree of accuracy. If your desktop computer is connected to the network it has an IP address or your local Wi-Fi router may have an SSID given by the router vendor or your Internet provider so the location of your desktop computer is not a secret, unless you change the SSID of your Wi-Fi router. Highly populated areas have more Wi-Fi routers and cell towers so the accuracy increases. In any case, properly designed applications must to always ask the user’s permission to use the current location of her computer or other connected device.

Note
The GPS signals are not always available. There are various location services that help identifying the position of your device. For example, Google, Apple, Microsoft, Skyhook and other companies use publicly broadcast Wi-Fi data from the wireless access point. Google Location Server uses Media Access Control (MAC) address to identify any device connected to the network.

Every Web Browser has a global object window, which includes the navigator object containing the information about the user’s browser. If the browser’s navigator object includes the property geolocation, geolocation services are available. While the Geolocation API allows you to get just a coordinate of your device and report the accuracy of this location, most applications use this information with some user-friendly UI, for example, the mapping software. In this section our goal is to demonstrate the following:

  1. How to use Geolocation API

  2. How to integrate the Geolocation API with Google Maps.

  3. How to detect id the Web browser supports geolocation services

Note
To respect people’s privacy, Web browsers will always ask for permission to use Geolocation API unless the user changes the settings one the browser to always allow it.

Geolocation Basics

The next version of our application is called project-07-basic-geolocation., where we simply assume that the Web browser supports the Geolocation. The Save The Child page will get a new container in the middle of the bottom main section, where we are planning to display the map of the current user location. But for now we’ll show there just the coordinates: latitude, longitude, and the accuracy. Initially, the map container is empty, but we’ll populate it from the JavaScript code as soon as the position of the computer is located.

<div id="map-container"></div>

The following code snippet from main.js makes a call to the navigator.geolocation object to get the current position of the user’s computer.

var mapContainer = document.getElementById('map-container');      // (1)

function successGeoData(position) {
	var successMessage = "We found your position!";               // (2)
	successMessage += '\n Latitude = ' + position.coords.latitude;
	successMessage += '\n Longitude = ' + position.coords.longitude;
	successMessage += '\n Accuracy = ' + position.coords.accuracy +
	console.log(successMessage);

	var successMessageHTML = successMessage.replace(/\n/g, '<br />');
	var currentContent = mapContainer.innerHTML;
	mapContainer.innerHTML = currentContent + "<br />"
	                                   + successMessageHTML;       // (3)

}

function failGeoData(error) {                                       // (4)
	console.log('error code = ' + error.code);

	switch(error.code) {
		case error.POSITION_UNAVALABLE:
			errorMessage = "Can't get the location";
			break;
		case error.PERMISSION_DENIED:
			errorMessage = "The user doesn't want to share location";
			break;
		case error.TIMEOUT:
			errorMessage = "Timeout -  Finding location takes too long";
			break;
		case error.UNKNOWN_ERROR:
			errorMessage = "Unknown error: " + error.code;
			break;
	}
	console.log(errorMessage);
	mapContainer.innerHTML = errorMessage;
}

if (navigator.geolocation) {
	var startMessage = 'Your browser supports geolocation API :)';
	console.log(startMessage);
	mapContainer.innerHTML = startMessage;
	console.log('Checking your position...');
	mapContainer.innerHTML = startMessage + '<br />Checking your position...';

	navigator.geolocation.getCurrentPosition(successGeoData,
	   failGeoData,                                            // (5)
	   {maximumAge : 60000,
		enableHighAccuracy : true,                             // (6)
		timeout : 5000
	   }
	);

} else {
	mapContainer.innerHTML ='Your browser does not support geolocation';
}
  1. Get a reference to the DOM element map-container to be used for showing the results.

  2. The function handler to be called in case of the successful discovery of the computer’s coordinates. If this function will be called it’ll get a position object as an argument.

  3. Display the retrieved data on the Web page (see The latitude and longitude are displayed).

  4. This is the error handler callback.

  5. Invoke the method getCurrentPosition() passing it two callback function as arguments (for success and failure) and an object with optional parameters for this invocation.

  6. Optional parameters: accept the cached value if not older than 60 seconds, retrieve the best possible results and don’t wait for results for more that 5 seconds. You may not always want the best possible results to lower the response time and the power consumption.

If you run the project-07-basic-geolocation, the Browser will show a popup (it can be located under the toolbar) asking you a question similar to "Would you like to share your location with 127.0.01?" Allow this sharing and you’ll see a Web page, which will include the information about your computer’s location similar to The latitude and longitude are displayed.

Tip
If you don’t see the question asking permission to share location, check the privacy settings of your Web browser - most likely you’ve allowed using your location some time in the past.
fig 03 15
Figure 15. The latitude and longitude are displayed
Tip
If you want to monitor the position as it changes (the device is moving) use geolocation.watchPosition(), which implements internal timer and checks the position. To stop monitoring position use geolocation.clearWatch().

Integrating with Google Maps

Knowing the device coordinates is very important, but let’s make the location information more presentable by feeding the device coordinates to Google Maps API. In this version of Save The Child we’ll replace the gray rectangle from <<>FIG3-15> with the Google maps container. We want the user to see a familiar map fragment with a pin pointing at the location of her Web browser. To follow our "Show and Tell" style let’s see it working first. Run the project-08-geolocation-maps and you’ll see a map with your current location as shown on Showing your current location.

fig 03 16
Figure 16. Showing your current location

Now comes the "Tell" part. First of all, take a look at the bottom of the index.html file. It loads Google’s JavaScript library with their Map API (sensor=false means that we are not using a sensor like GPS locator):

<script src="http://maps.googleapis.com/maps/api/js?sensor=false"></script>

In the past Google required developed to obtain an API key and include it in the above URL. Although some Google’s tutorials still mentions the API key, it’s not a must.

Note
An alternative way of adding the <script> section to HTML page is by creating a script element. This gives you a flexibility of postponing the decision of which JavaScript to load. For example,
var myScript=document.createElement("script");
myScript.src="http://......somelibrary.js";
document.body.appendChild(myScript);

Our main.js will invoke the function for Google’s library as needed. The code that finds the location of your device is almost the same as in the section Geolocation Basics. We’ve replaced the call to with geolocation.watchPosition() so this program can modify the position if your computer, tablet, or a mobile phone is moving. We store the returned value of the watchPosition() in the variable watcherID in case if you decide to stop watching the position of the device by calling clearWatch(watcherID). Also, we lowered the value of the maximumAge option so the program will update the UI more frequently, which is important if you are running this program while in motion.

(function() {

 var locationUI = document.getElementById('location-ui');
 var locationMap = document.getElementById('location-map');
 var watcherID;

 function successGeoData(position) {
   var successMessage = "We found your position!";
   var latitude = position.coords.latitude;

   var longitude = position.coords.longitude;
   successMessage += '\n Latitude = ' + latitude;
   successMessage += '\n Longitude = ' + longitude;
   successMessage += '\n Accuracy = ' + position.coords.accuracy
                                      + ' meters';
   console.log(successMessage);

   // Turn the geolocation position into a LatLng object.
   var locationCoordinates =
          new google.maps.LatLng(latitude, longitude);      // (1)

   var mapOptions = {
   	center : locationCoordinates,
   	zoom : 12,
   	mapTypeId : google.maps.MapTypeId.ROADMAP,         //  (2)
   	mapTypeControlOptions : {
   	  style : google.maps.MapTypeControlStyle.DROPDOWN_MENU,
   	  position : google.maps.ControlPosition.TOP_RIGHT
   	}
   };

   // Create the map
   var map = new google.maps.Map(locationMap, mapOptions);  // (3)

   // set the marker and info window
   var contentString = '<div id="info-window-content">' +
        'We have located you using HTML5 Geolocation.</div>';

   var infowindow = new google.maps.InfoWindow({            // (4)
   	content : contentString,
   	maxWidth : 160
   });

   var marker = new google.maps.Marker({                   //  (5)
   	position : locationCoordinates,
   	map : map,
   	title : "Your current location"

   });

       google.maps.event.addListener(marker, 'click',      // (6)
            function() {
                infowindow.open(map, marker);
            }
       );

       // When the map is loaded show the message and
       // remove event handler after the first "idle" event
       google.maps.event.addListenerOnce(map, 'idle', function(){
   	locationUI.innerHTML = "Your current location";
   })

 }

  // error handler
 function failGeoData(error) {
 	 clearWatch(watcherID);
 	//the error processing code is omitted for brevity
 }

 if (navigator.geolocation) {
 	var startMessage =
 	    'Browser supports geolocation API. Checking your location...';
 	console.log(startMessage);

 	var currentContent = locationUI.innerHTML;
 	locationUI.innerHTML = currentContent +' '+startMessage;

 	watcherID = navigator.geolocation.watchPosition(successGeoData,  // (7)
 	    failGeoData, {
 		maximumAge : 1000,
 		enableHighAccuracy : true,
 		timeout : 5000
 	});

 } else {
 	console.log('browser does not support geolocation :(');
 }
})();
  1. Google API represents a point in geographical coordinates (latitude and longitude) as a LatLng object, which we instantiate here.

  2. The object`google.maps.MapOptions` is an object that allows you to specify various parameters of the map to be created. In particular, the map type can be one of the following: HYBRID, ROADMAP, SATTELITE, TERRAIN. We’ve chosen the ROADMAP, which displays a normal street map.

  3. The function constructor google.maps.Map takes two arguments: the HTML container where the map has to be rendered and the MapOption as parameters of the map.

  4. Create an overlay box that will show the content describing the location (e.g. a restaurant name) on the map. You can do it programmatically by calling InfoWindow.open().

  5. Place a marker on the specified position on the map.

  6. Show the overlay box when the use clicks on the marker on the map.

  7. Invoke the method watchPosition() to find the current position of the user’s computer.

This is a pretty basic example of the integrating GeoLocation with the mapping software. Google Maps API consists of dozens JavaScript objects and supports various events that allow you to build interactive and engaging Web pages that include maps. Refer to the Google Maps JavaScript API Reference for the complete list of available parameters (properties) of all objects used in project-08-geolocation-maps and more. In Chapter 2 you’ll see a more advanced example of using Google maps - we’ll read the JSON data stream containing coordinates of the children so the donors can find them based on the specified postal code.

Tip
For a great illustration of using Google Maps API look at the PadMapper Web application. We use it for finding rental apartments in Manhattan.

Browser Features Detection With Modernizr

Now we’ll learn how to use the detection features offered by a JavaScript library called Modernizr. This is a must have feature detection library that helps your application to figure out if the user’s browser supports certain HTML5/CSS3 features. Review the code of index.html from the project-08-1-modernizr-geolocation-maps. Note that the index.html includes two <script> sections - the Modernizr’s JavaScript gets loaded first, while our own main.js is loaded at the end of the <body> section.

<!DOCTYPE html>

<html class="no-js" lang="en">
	<head>
		<meta charset="utf-8">

		<title>Save The Child | Home Page</title>
		<link rel="stylesheet" href="assets/css/styles.css">

		<script src="js/libs/modernizr-2.5.3.min.js"></script>

	</head>
	<body>
       !--  Most of the HTML markup is omitted for brevity  --!

		<script src="js/main.js"></script>
	</body>
</html>

Modernizr is an open source JavaScript library that helps your script to figure out if the required HTML or CSS features are supported by the user’s browser. Instead of maintaining complex cross-browser feature matrix to see if, say border-radius is supported in the user’s version of Firefox, the Modernizer queries the <html> elements to see what’s supported and what’s not.

Note the following fragment on the top of index.html: <html class="no-js" lang="en">. For Modernizr to work, your HTML root element has to include the class named "no-js". On page load, the Modernizr will replace the no-js class with its extended version that lists all detected features, and those that are not supported will get a prefix no-. Run index.html from project-08-1-modernizr-geolocation-maps in Chrome and you’ll see using Developer Tools Panel that the values of the class property of the html element are different now, and you can see from Modernizr changed the HTML’s class property that our version of Chrome doesn’t support touch events (no-touch) and flexbox (no-flexbox).

fig 03 17
Figure 17. Modernizr changed the HTML’s class property

For example, there is a new way to do page layouts using co called CSS Flexible Box Layout Module. This feature is not widely supported yet, and as you can see from Modernizr changed the HTML’s class property, our Web browser doesn’t support it at the time of this writing. If the CSS file of your application will implement two class selectors .flexbox and .no-flexbox then the browsers that support flexible boxes will use the former and the older browsers - the latter.

When Modernizr loads it creates a new JavaScript object window.Modernizr with lots of boolean properties indicating if a certain feature is or is not supported. Add the Modernizr object as a Watch Expression in the Chrome Developer Tools panel and see which properties have the false value (see window.Modernizr object).

fig 03 18
Figure 18. window.Modernizr object

Hence your JavaScript code can test if certain features are supported or not.

What if the Modernizer detects that a certain feature is not supported yet by a user’s older browser? You can include polyfills in your code that replicate the required functionality. You can write such a polyfill on your own or pick one from the collection that is located at Modernizr’s Github repository.

The Development version of Modernizr weighs 42Kb and can detect lots of features. But you can make it smaller by configuring the detection of only selected features. Just visit Modernizr and press the red Production button that will allow to configure the build specifically for your application. For example, if you’re just interested to detect the HTML5 video support, the size of the generated Modernizr library will be reduced to under 2Kb.

Let’s review the relevant code from project-08-1-modernizr-geolocation-maps that illustrate the use of Modernizr. In particular, Modernizr allows you to load one or the other JavaScript code based on the result of some tests.

NOTE: Actually, the Modernizr loader internally utilizes a tiny (under 2Kb) resource loader library yepnope.js, which can load both JavaScript and CSS. This library is integrated in Modernizr, but we just wanted to give a proper recognition to yepnope.js, which can be used as an independent resource loader too.

(function() {

  Modernizr.load({

  	test: Modernizr.geolocation,

  	yep: ['js/get-native-geo-data.js','https://www.google.com/jsapi'],

  	nope: ['js/get-geo-data-by-ip.js','https://www.google.com/jsapi'],

  	complete : function () {
  		google.load("maps", "3",
  		            {other_params: "sensor=false", 'callback':init});
  	}
  });
})();

The code above invokes the function load(), which can take different arguments, but our example uses as an argument a specially prepared object with five properties: test, yep, nope, complete. The load() function will test the value of Modernizr.geolocation and if it’s true, it’ll load the scripts listed in the yep property. Otherwise it’ll load the code listed in the nope array. The code in the get-native-geo-data.js gets the user’s location the same way as it was done earlier in the section Integrating with Google Maps.

Now let’s consider the "nope" case. The code of the get-geo-data-by-ip.js has to offer an alternative way of getting the location for the browsers that don’t support HTML5 Geolocation API. We found the GeoIP JavaScript API offered by MaxMind, Inc.. Their service returns country, region, city, latitude and longitude, which can serve as a good illustration of how a workaround of a non-supported feature can be implemented. The code in get-geo-data-by-ip.js is very simple for now.

function init(){

 var locationMap = document.getElementById('location-map');
 locationMap.innerHTML="Your browser does not support HTML5 geolocation API.";

 // The code to get the location by IP from http://j.maxmind.com/app/geoip.js
 // will go here. Then we'll pass the latitude and longitude values to
 // Google Map API for drawing the map.

}

Most likely your browser supports HTML5 geolocation API, and you’ll see the map created by the script get-native-geo-data.js. But if you want to test a non-supported geolocation (the nope branch) either try this code in the older browser or change the test condition to look like this: Modernizr.fakegeolocation,.

Google has several JavaScript APIs, for example, Maps, Search, Feeds, Earths et al. Any of these APIs can be loaded by Google AJAX Loader google.load(). This is more generic way of loading any APIs comparing to loading maps from http://maps.googleapis.com/maps/api in the previous section on integrating geolocation and maps. The process of loading of the Google code with Google AJAX Loader consists of two steps:

  1. Load Google’s common loader script from https://www.google.com/jsapi

  2. Load the concrete module API specifying its name, version and optional parameters. In our example we are loading the maps API of version 3 passing an object with two properties: sensor=false and the name of the callback function to invoke right after the mapping API completes loading: 'callback':init.

Tip
If you want to test your Web page in the specific old version of a particular Web browser, you can find their distributions at oldapps.com. For example, you can find all the old version of Firefox for Mac OS and for Windows.

Search and Multi-Markers With Google Maps

We’ve prepared for you a couple of more examples just to showcase the features of Google Maps API. The working examples will be included in the code accompanying the book, and we’ll provide very brief explanations below.

The project-09-map-and-search is an example of address search using Google Maps API. Searching by Address shows a fragment of the Save The Child page after we’ve entered the address "26 Broadway ny ny" in the search field. You can do a search by city or a zip code too. This can be a useful feature if you’d want to allow the users search for the children living in a particular geographical area so their donation would be directed to specific people.

fig 03 19
Figure 19. Searching by Address

Our implementation of the search is shown in the code fragment from main.js. It uses geocoding, which is a process of converting an address into geographic coordinates (latitude and longitude). If the address is found, the code places a marker on the map.

var geocoder = new google.maps.Geocoder();

function getMapByAddress() {
 var newaddress = document.getElementById('newaddress').value;

 geocoder.geocode(                                    //  (1)
  {'address' : newaddress,
  'country' : 'USA'
  },

  function(results, status) {                       //  (2)
   console.log('status = ' + status);

   if (status == google.maps.GeocoderStatus.OK) {

  	var latitude = results[0].geometry.location.lat();          // (3)
  	var longitude = results[0].geometry.location.lng();

  	var formattedAddress = results[0].formatted_address;
  	console.log('latitude = ' + latitude +
  	            ' longitude = ' +  longitude);
  	console.log('formatted_address = ' + formattedAddress);

  	var message = '<b>Address</b>: ' + formattedAddress;
  	foundInfo.innerHTML = message;

  	var locationCoordinates =
  	      new google.maps.LatLng(latitude, longitude);         // (4)
  	showMap(locationCoordinates, locationMap);

   } else if (status == google.maps.GeocoderStatus.ZERO_RESULTS) { // (5)
  	console.log('geocode was successful but returned no results. ' +
  	 'This may occur if the geocode was passed a non-existent ' +
  	 'address or a latlng in a remote location.');

   } else if (status == google.maps.GeocoderStatus.OVER_QUERY_LIMIT) {
  	console.log('You are over our quota of requests.');

   } else if (status == google.maps.GeocoderStatus.REQUEST_DENIED) {
  	console.log('Your request was denied, ' +
  	'generally because of lack of a sensor parameter.');

   } else if (status == google.maps.GeocoderStatus.INVALID_REQUEST) {
  	console.log('Invalid request. ' +
  	     'The query (address or latlng) is missing.');
  }
 });
}
  1. Initiate request to the Gecoder object providing the GeocodeRequest object with the address and a function to process the results. Since the request to the Google server is asynchronous, the function is a callback.

  2. When the callback will be invoked, it’ll get an array with results.

  3. Get the latitude and longitude from the result.

  4. Prepare the LatLng object and give it to the mapping API for rendering.

  5. Process errors.

The Geocoding API is simple and free to use until your application reaches a certain number of requests. Refer to Google Geocoding API documentation for more details. If your application is getting the OVER_QUERY_LIMIT you ned to contact Google Maps API for Business sales team for information on licensing options.

Adding Multiple Markers on the Map

Jerry has yet another idea: show multiple markers on the map reflecting several donation campaigns and charity events that are going on at various locations. If we display this information on the Save The Child page more people may participate with their donations or other ways. We’ve just learned how to do an address search on the map, and if the application has an access to the data about charity events, we can display them as the markers on the map. Run the project-10-maps-multi-markers and you’ll see a map with multiple markers as in Multiple markers on the map

fig 03 20
Figure 20. Multiple markers on the map

The JavaScript fragment below displays the map with multiple markers. In this example the data is hard-coded in the array charityEvents, but in the next chapter we’ll modify this example and will get the data from a file in a JSON form. The for-loop creates a marker for each of the event listed in the array charityEvents. Each element of this array is also an array containing the name of the city and state, the latitude and longitude, and the title of the charity event. You can have any other attributes of the charity events stored in such an array and display them when the user clicks on a particular marker in an overlay by calling InfoWindow.open().

(function() {

  var locationUI = document.getElementById('location-ui');
  var locationMap = document.getElementById('location-map');

  var charityEvents = [['Chicago, Il', 41.87, -87.62, 'Giving Hand'],
    ['New York, NY', 40.71, -74.00, 'Lawyers for Children'],
    ['Dallas, TX', 32.80, -96.76, 'Mothers of Asthmatics '],
    ['Miami, FL', 25.78, -80.22, 'Friends of Blind Kids'],
    ['Miami, FL', 25.78, -80.22, 'A Place Called Home'],
    ['Fargo, ND', 46.87, -96.78, 'Marathon for Survivors']
  ];

  var mapOptions = {
  		center : new google.maps.LatLng(46.87, -96.78),
  		zoom : 3,
  		mapTypeId : google.maps.MapTypeId.ROADMAP,
  		mapTypeControlOptions : {
  			style : google.maps.MapTypeControlStyle.DROPDOWN_MENU,
  			position : google.maps.ControlPosition.TOP_RIGHT
  		}
  	};

  var map = new google.maps.Map(locationMap, mapOptions);

  var infowindow = new google.maps.InfoWindow();

  var marker, i;

  for ( i = 0; i < charityEvents.length; i++) {
  	marker = new google.maps.Marker({
  		position : new google.maps.LatLng(charityEvents[i][1],
  		                                  charityEvents[i][2]),
  		map : map
  	});

  	google.maps.event.addListener(marker, 'click', (function(marker, i) {
  		return function() {
  		 var content = charityEvents[i][0] + '<br/>' + charityEvents[i][3];
  		 infowindow.setContent(content);
  		 infowindow.open(map, marker);
  		}
  	})(marker, i));

  	google.maps.event.addListenerOnce(map, 'idle', function(){
  		locationUI.innerHTML = "Donation campaigns and charity events.";
  	})
  }

})();

Summary

This chapter has described the process of mocking the future Web site on by our Web Designer Jerry, who went a lot further than creating a number of images with short descriptions. Jerry created a working prototype of the Save The Child page. Keep in mind that Jerry and his fellow Web designers like creating good looking Web pages.

But us, Web developers, need to worry about other things like making Web pages responsive and light weight. The first thing you need to do after receiving the prototype of your Web application from Jerry is run it through Google Developer Tools or Firebug and measure the total size of the resources being downloaded from the server. If it loads 1Mb or more worth of images, ask Jerry to review the images and minimize their size.

The chances are that you don’t need to download all the JavaScript code at once - we’ll discuss modularization of large applications in Chapter 6.

The next phase of improving this prototype is to remove the hard-coded data from the code and place them into external files. The next chapter will cover the JSON data format and how to fill our single-page application with the data using a set of techniques called AJAX.