Implementing UI Navigation in the Boilerplate

Implementing UI Navigation in the Boilerplate

===

Implementing UI Navigation in the Boilerplate

With the interface laid out as required, we will now flesh out other parts of our application interface. First, we will make some simple modifications to the HTML to include a child view div that will provide us with the ability to select a marker, tap the marker title, and get more information on that location.

The modifications to the mapapp.html are as follows: <!DOCTYPE html>

<html> ... <div id="marker-nav">

<img src="../../img/navigation-arrow.png" class="left disabled" /> <span class='marker-title'>Test Text</span> <img src="../../img/navigation-arrow.png" class="right" />

</div>

<div id="marker-detail" class="child-screen"> <div class='content'>Some Test Content</div> <button class='close'>Close</button>

</div>

</body> </html>

The marker-detail div is added just before the end of the body tag, and just after the marker-nav div that we created earlier. Making these changes to the HTML will break the map display, and the following additional CSS rules are required to bring everything back to displaying correctly. Add the following CSS to the end of the mapapp.css file:

div.child-screen { background: rgba(255, 255, 255, 0.75); width: 100%; height: 100%;

Download from Wow! eBook <www.wowebook.com>

left: 100%;

top: 0px; position: absolute; z-index: 91;

} div.child-screen .content {

margin: 50px 10px 0; }

div.child-screen button.close { height: 30px; position: absolute; bottom: 10px; left: 10px; right: 10px; display: block;

} Notice that the CSS rules specify that a div of class child-screen will be displayed with

absolute positioning and have a height and width of 100%. This means that these div elements, like the map, will take up the entire screen when displayed. What stops this

CHAPTER 8: Location-Based Services and Mobile Mapping

screen from displaying when the HTML is first rendered is the absolute left position specified at 100% (shown in bold).

This works in conjunction with the overflow: hidden CSS from the previous code to hide the div off the right side of the map until we need it.

When we require the child-screen div to display, we dynamically set the left position of the div to 0px. In terms of visual styling, we apply a background fill using the rgba CSS function to display a slightly transparent white background. This provides a nice visual effect, in which the map is still slightly visible under the child screen that has been activated. The z-index of 91 places it above the HTML elements on the map screen, but beneath the h1 title.

Finally, make the following modifications to the mapapp.js file to properly activate the navigation flow:

MAPAPP = (function() { // initialize constants var DEFAULT_ZOOM = 8;

// initialize variables var map = null,

mainScreen = true,

function activateMarker(marker) { // update the navbar title using jQuery $('#marker-nav .marker-title')

.html(marker.getTitle()) .removeClass('has-detail') .unbind('click');

// if content has been provided, then add the has-detail // class to adjust the display to be "link-like" and // attach the click event handler var content = markerContent[marker.getTitle()]; if (content) {

$('#marker-nav .marker-title') .addClass('has-detail') .click(function() {

$('#marker-detail .content').html(content); showScreen('marker-detail');

}); } // if } // activateMarker

function addMarker(position, title, content) { // create a new marker to and display it on the map var marker = new google.maps.Marker({

position: position, map: map, title: title

CHAPTER 8: Location-Based Services and Mobile Mapping

// save the marker content markerContent[title] = content;

// add the marker to the array of markers markers.push(marker);

// if the first marker, activate automatically if (markers.length === 1) {

activateMarker(marker, content); } // if

// capture touch click events for the created marker google.maps.event.addListener(marker, 'click', function() {

// activate the clicked marker activateMarker(marker);

}); } // addMarker

function initScreen() { // watch for location hash changes

setInterval(watchHash, 10);

// next attach a click handler to all close buttons $('button.close').click(showScreen);

} // initScreen

function showScreen(screenId) {

mainScreen = typeof screenId !== 'string'; if (typeof screenId === 'string') {

$('#' + screenId).css('left', '0px');

// update the location hash to marker detail window.location.hash = screenId;

} else {

$('div.child-screen').css('left', '100%'); window.location.hash = '';

} // if..else

scrollTo(0, 1); } // showScreen

function watchHash() { // this function monitors the location hash for a reset to empty if ((! mainScreen) && (window.location.hash === ') {

showScreen(); } // if } // watchHash

var module = { addMarker: addMarker,

init: function(position, zoomLevel) {

// initialize the screen

CHAPTER 8: Location-Based Services and Mobile Mapping

initScreen(); } };

return module; })();

In the preceding code, the showScreen function does most of the legwork. When it is passed a string parameter (which it checks for using the JavaScript typeof operator), it uses jQuery to bring that HTML element into view by adjusting its left position. This works in conjunction with the previously defined CSS to bring in and hide separate views in the main application viewing area. To the end user, this provides a similar experience to what we coded in the earlier to-do list application. In this case, however, we are using absolute positioning based on the presence and requirements of the map component.

Another notable part of the code is the watchHash function, which is called at regular intervals (courtesy of the JavaScript setInterval function). The purpose of the function is to monitor the window.location.hash property and keep the application UI in sync. This means that the user will be able to use the back button on the browser, in addition to the Close button, which is placed in a child view to navigate back to the main screen.

Finally, we update the addMarker function to save the marker content into the markerContent object for each of the marker titles, and also call a new function ( activateMarker) when a marker is clicked—rather than simply updating the title. At first glance, the activateMarker code may appear a little complicated, but it’s reasonably simple once you break it down:

1. First, HTML elements with the marker-title class are updated with the title of the marker (retrieved using the marker.getTitle method). At the same time, the has- detail class is removed, and we unbind the click event handler, as the marker may not actually have any content and therefore no detail screen. The has-detail class was defined in the previous section’s boilerplate CSS to simply show an underline under the text, thereby simulating a link.

2. Second, if the marker has content associated, then we add the has-detail class and bind a click handler to the marker title. Now, when the user clicks the marker title, they will be taken to the marker-detail screen and shown the HTML content that was specified for the marker.

With these modifications complete, we will be able to navigate to our placeholder child view by clicking the marker title that will be displayed underlined in the navigation bar. Figure 8–10 illustrates this.

CHAPTER 8: Location-Based Services and Mobile Mapping

NOTE: You might be wondering why we are reimplementing functionality that we have already covered in our previous to-do list application. This is because the navigation code we implemented as part of our to-do list application doesn’t work well with the recommended Google Maps layout. Rather than attempt to retrofit the code to suit the Google Maps code, it was

a simpler exercise to create a separate mapping application boilerplate. As mentioned earlier in the book, the mobile web app space is crying out for a mature, mobile

JavaScript framework that will take care of some of the grunt work that is involved with writing a mobile web app.

There are already some good contenders out there, but Android and other mobile device support isn’t very extensive yet. My money is definitely on jQuery Mobile in the long run. This will hopefully be released shortly before this book, but not at the time of writing unfortunately.

Figure 8–10. We are now able to navigate to a subscreen by clicking the marker title in the nav bar.