Tabula Rasa: Nurturing your Site for Tablets

Packt Publishing

Transform your existing Drupal site into one that is completely compatible with mobile and tablet devices with this book and ebook

The human touch

There's a reason touchscreen interfaces were rarely used before Apple re-invented them in the iPhone. It's because programming them is very difficult. With a mouse-driven interface you have a single point of contact: the mouse's pointer. With a touchscreen, you potentially have ten points of contact, each one with a separate motion. And you also have to deal with limiting spurious input when the user accidentally touches the tablet when they didn't mean to. Does the user's swipe downward mean they want to scroll the page or to drag a single page element? The questions go on to infinity.

With this article, we stand on the shoulders of those giants who have done the heavy lifting and given us a JavaScript interface that registers touch and gestures for use in our web pages. Many Bothans died to bring us this information.

To understand the tablet is to understand the touch interface, and in order to understand the touch interface, we need to learn how touch events differ from mouse events. But that begs the question: what is an event?

The event-driven model

Many developers use JavaScript-based events and have not even the slightest clue as to what they can do or their power. In addition, many developers get into situations where they don't know why their events are misfiring or, worse yet, bubbling to other event handlers and causing a cascade of event activity.

As you may or may not know, an HTML document is made up of a series of tags organized in a hierarchical structure called the HTML document. In JavaScript, this document is referred to through the reserved word document. Simple enough, right? Well, what if I want to interact with the tag inside of a document, and not the document as a whole? Well, for that we need a way of addressing nested items inside the main <html> tag. For that, we use the Document Object Model (DOM).

DOM is a cross-platform and language-independent convention for representing and interacting with objects in HTML, XHTML, and XML documents. Aspects of the DOM (such as its elements) may be addressed and manipulated within the syntax of the programming language in use. The public interface of a DOM is specified in its Application Programming Interface (API). For more details on DOM, refer to the Wikipedia document at: http://en.wikipedia.org/wiki/Document_Object_Model.

The body of that document then becomes document.body. The head of the document, likewise, becomes document.head. Now, what happens when your mouse interacts with this web page? This is said to be a DOM event. When you click, the elements that are the receivers of that action are said to propagate the event through the DOM. In the early days, Microsoft and Netscape/Firefox had competing ways of handling those events. But they finally gave way to the modern W3C's standard, which unifies the two ways and, even more importantly, jQuery has done a lot to standardize the way we think about events and event handling. In most browsers today, mouse events are pretty standardized, as we are now more than 20 years into the mouse-enabled computing era:

For tablets and touchscreen phones, obviously, there is no mouse. There are only your fingers to serve the purpose of the mouse. And here's where things get simultaneously complicated as well as simple.

Touch and go

Much of what we talk about as touch interaction is made up of two distinct types of touches—single touches and gestures. A single touch is exactly that. One finger placed on the screen from the start till the end. A gesture is defined as one or more fingers touching the surface of the area and accompanied by a specific motion: Touch + Motion. To open most tablets, you swipe your finger across a specific area. To scroll inside a div element, you use two fingers pushing up and down. In fact, scrolling itself is a gesture and tablets only respond to the scroll event once it's over. We will cover more on that later.

Gestures have redefined user interaction. I wonder how long it took for someone to figure out that the zoom in and zoom out is best accomplished with a pinch of the fingers? It seems so obvious once you do it and it immediately becomes second nature. My mom was pinching to zoom on her iPhone within the first 5 minutes of owning it.

Touch events are very similar to multiple mouse events without a hover state. There is no response from the device when a finger is over the device but has not pressed down. There is an effort on the part of many mobile OS makers to simulate the hover event by allowing the hover event to trigger with the first click, and the click event to trigger with the second click on the same object. I would advise against using it for any meaningful user interaction as it is inconsistently implemented, and many times the single click triggers the link as well as the hover-reveal in drop-down menus.

Not using the hover event to guide users through navigation changes the way we interact with a web page. Much of the work we've done to guide users through our pages is based on the hover-response event model to clue users in on where links are. We have to get beyond that.

Drop-down menus quickly become frustrating at the second and third levels, especially if the click and hover events were incorrectly implemented in the desktop browser. Forward and back buttons are rendered obsolete by a forward and backwards swipe gesture.

The main event

There are basically three touch events—touchstart, touchmove, and touchend. Gesture events are, likewise: gesturestart, gesturemove, and gestureend. All gestures register a touch event but not all touch events register gestures. Gestures are registered when multiple fingers make contact with the touch surface and register significant location change in a concerted effort, such as two or more fingers swiping, a pinch action, and so on.

In general, I've found it a good practice to use touch events to register finger actions; but it is required to return null on a touch event when there are multiple fingers involved and to handle such events with gestures.

jQuery mobile has a nice suite of touch events built into its core that we can hook into. But jQuery and jQuery mobile sometimes fall short of the interaction we want to have for our users, so we'll outline best practices for adding customized user touch events to both the full and mobile version of the demo site.

Let's get started…

Time for action – adding a swipe advance to the home page

The JavaScript to handle touch events is a little tricky; so, pay attention:

Add the following lines to both sites/all/themes/dpk/js/global.js and sites/all/themes/dpk_mobile/js/global.js:

Clear Drupal's cache by either navigating to Configuration | Performance and clicking on the Clear cache button or entering these lines in a terminal:

cd ~/sites/dpk/drush cc all

Navigate to either home page with a touch-enabled device and you should be able to advance the home page slideshow with your fingers.

What just happened?

Let's take a look at how this code works. First, we have a function, isTouchDevice. This function returns true/false values if touch events are enabled on the browser. We use an if statement to wall off the touchscreen code, so browsers that aren't capable don't register an error. The Drupal behavior jQueryMobileSlideShowTouchAdvance has the attach and detach functions to satisfy the Drupal behavior API. In each function, we locally assign the self variable with the value of the entire object. We'll use this in place of the this keyword. In the Drupal behavior object, this can sometimes ambiguously refer to the entire object, or to the current sub-object. In this case, we want the reference to be to just the sub-object so we assign it to self. The attach function grabs all slideshow_cycle div elements in a jQuery each loop. The iteration of the loop adds an event listener to the div tag. It's important to note that the event listener is not bound with jQuery event binding. jQuery event binding does not yet support touch events. There's an effort to add them, but they are not in the general release that is used with Drupal 7. We must then add them with the browser native function, AddEventListener. We use the handleTouchStart method to respond to the touchstart event. We will add touchend and touchmove events after the touchstart is triggered.The other event that we're adding listens to this object for the swipe event. This is a custom event we will create that will be triggered when a swipe action happens. We will cover more on that shortly.The detach function is used to add cleanup to items when they are removed from the DOM. Currently, we have no interaction that removes items from the DOM and therefore no cleanup that's necessary for that removal to take place.Next, we add some defaults—original, changed, direction, and fired. We'll use those properties in our event response methods.HandleTouchStart event is fired when the finger first touches the surface. We make sure the evt.touches object has value and is only one touch. We want to disregard touches that are gestures. Also, we use preventDefault and stopPropagation on the event to keep it from bubbling up to other items in the DOM. self.original is the variable that will hold the touch's original coordinates. We store the values for touch[0]. We also name the target by getting the DOM ID of the cycle containing the div element. We can use string transforms on that ID to obtain the ID of the jQuery cycle being touched and will use that value when we send messages to the slideshow, based on the touch actions, like we do in the next line. We tell the slideshow to pause normal activity while we figure out what the user wants. To figure that out, we add touchmove and touchend events listening to the div element. handleTouchMove figures out the changed touch value. It does so by looking at the ClientX and ClientY values in the touch event.Some browsers support the changedTouches value which will do some calculations on how much the touch has changed since the last event was triggered. If it's available, we use it, or we use the value of the X and Y coordinates in the touch event's touches array. We do some subtraction against the original touch to find out how much the touch has changed and in what direction. We use self.direction to store the direction of the change. We store the direction in and tell the world that a swipe has begun on our div element by triggering a custom event on our self object.If you remember correctly, we used the handleSwipe method to respond to the swipe event. In handleSwipe we make sure the event has not already fired. If it hasn't, we use that swipe event to trigger a next or previous action on our jQuery cycle slideshow. Once we've fired the event, we change the self.fired to true so it will only fire once per touch. In the touchend responder, HandleTouchEnd, we remove both the touchmove and touchend responders and reset the fired state.But adding the touch events to both the desktop and the mobile themes begs the question, "Into which category does the table fall?"

Have a go hero – adding a swipe gesture

Add a swipe gesture event to the Menu Item page that allows you to scroll through menu items.

The changing landscape (or portrait)

Responsive web design is a design discipline that believes that the same markup should be used for both desktop and mobile screens, with the browser managing the display of items, rather than the user choosing an experience. If the screen is smaller, the layout adjusts and content emphasis remains.Conversely, the popularity of Internet-connected game consoles and DVI ports on large screen televisions gives us yet another paradigm for web pages—the large screen. I sit in front of a 72" TV screen and connect it to either my laptop or iPad and I have a browsing experience that is more passive, but completely immersive.Right now, I bet you're thinking, "So which is it Mr Author, two sites or one?" Well, both, actually. In some cases, with some interactions it will be necessary to do two site themes and maintain them both. In some cases, when you can start from scratch, you can do a design that can work on every browser screen size. Let's start over and put responsive design principals to work with what we already know about media queries and touch interfaces.

"Starting over" or "Everything you know about designing websites is wrong"

Responsive web design forces the designer to start over—to forget the artificial limitations of the size that print imposes and to start with a blank canvas. Once that blank canvas is in place, though, how do you fill it? How do you create "The One True Design" (cue the theme music)?This book is not a treatise on how to create the perfect design. For that, I can recommend A Book Apart and anything published by smashingmagazine.com. Currently, they are at the forefront of this movement and regularly publish ideas and information that is helpful without too much technical jargon.No, this book is more about giving you strategies to implement the designs you're given or that you create using Drupal. In point of fact, responsive design, at the time of writing, is in its infancy and will change significantly over the next 10 years, as new technology forces us to rethink our assumptions about what books, television, and movies are and what the Web is.So suffice to say, it begins with content. Prioritizing content is the job of the designer. Items you want the user to perceive first, second, and third are the organizing structure of your responsive design makeover. In most instances, it's helpful to present the web developer with four views of the website.

Wire framing made easy

Start with wireframes. A great wire framing tool is called Balsamiq. It has a purposefully "rough" look to all of the elements you use. That way, it makes you focus on the elements and leave the design for a later stage. It's also helpful for focusing clients on the elements. Many times the stake holders see a mockup and immediately begin the discussion of "I like blue but I don't like green/I like this font, but don't like that one." It can be difficult to move the stake holders out of this mindset, but presenting them with black-and-white chalk-style drawings of website elements can, in many cases, be helpful. Balsamiq is a great tool for doing just that:

These were created with Balsamiq but could have been created in almost any primitive drawing program. There are many free ones as well as the more specialized pay ones. A simple layout like this is very easy to plan and implement. But very few of the websites you develop will ever be this simple. Let's take for instance that the menu item we have not, as yet, implemented, is for online ordering. How does that work? What do those screens look like? At this point we have a Menu page but, as per this mockup, that menu page will become the online ordering section. How do we move these menu items we created to a place where they can be put in an order and paid for? And more importantly, how does each location know what was ordered from their location?These are questions that come up in the mockup and requirements phase and whether you are building the site yourself or being given requirements from a superior, or a client, you now have a better idea of the challenges you will face implementing the single design for this site. With that, we've been given these mockups for the new online ordering system. The following mockup diagram is for adding an order:

The following mockup diagram is for placing an order:

We'll implement these mockups using the Drupal 7 Commerce module. The Commerce module is just a series of customized data entities and views that we can use as the building blocks of our commerce portion. We'll theme the views in the standard Drupal way but with an eye to multi-width screens, lack of hover state, and keeping in mind "hit zones" with fingers on small mobile devices. We'll also add some location awareness to assist with the delivery process. Once an order is placed, an e-mail will need to be sent to the correct franchise notifying them of the pizza order and initiating the process of getting it out the door.

Drupal 7 Commerce module

There are some things you need to know about the Commerce module before we begin. There are several steps to creating a product to be sold and then getting that product into a cart to checkout.

The first step is to create the product type. The product type is a kind of a content type for nodes. It defines the basic structure and fields that the item will have.

Once you've created the product type you can create products of that type. Simply to the nodes themselves, products are instances of their product type. Each product may have variations that will affect the price, such as size, and in the case of a pizza, it's toppings. Once you've created the product type and have products of that type, you can create a cart line item to receive that product into the cart. The cart line item will allow you to show what product options are applied to that specific product instance.

Now that the product portion is created, you need to connect it with the rest of the Drupal universe. That's where product references come in. The product reference field is a field type that can be added to a note to connect it to a product. You can then add a link to the product to add it to the cart, as we will do in the Time for action – the one true theme section:

Product type

Product

Cart line item

Node product reference field

Analogous to content types for nodes. Defines the fields and options for a given product group.

Analogous to nodes but with pricing and features that may or may not alter pricing.

Shopping cart container that holds information about what product options were selected by the user as well as pricing based on those options.

Allows nodes to point to product entities. Connects products with the rest of Drupal nodes.

Confused? It may make more sense when you see it in action. We've got a lot of work to do. Ready to begin?

Time for action – the one true theme

Let's download, install, and configure the Drupal Commerce module:

Open a terminal window and enter the following command:

drush dl rules addressfield commerce commerce_custom_line_items

It doesn't make sense to enable all of the modules that come with Drupal Commerce with Drush, so just navigate to Sites | Modules and ensure that all of the following modules are enabled: Cart, Checkout, Commerce, Commerce UI, Customer, Customer UI, Line Item, Line Item UI, Order, Order UI, Payment, Payment Method Example, Payment UI, Price, Product, Product Pricing, Product Pricing UI, Product Reference, Product UI, Tax, Tax UI, Commerce Custom Line Items.

Under Add new field, add a field called Size with the machine name field_size and the List (text) type displayed with the Checkboxes/radio buttons widget. Click on Save. On the Pizza settings screen, make the Allowed values field as follows. Then click on Save:

0|Large16|Medium14|Small

On the final settings page, make the Size field as a required field with the default value of Large. Under Attribute field settings make sure Enable this field to function as an attribute field on Add to Cart forms is checked and use the radio buttons widget. Save the new field.

Create a new field called Toppings with the machine name field_toppings and the List (text) type displayed with the Checkboxes/radio buttons widget. Click on Save. Use the following settings for the Allowed values field, and then click on Save:

On the final settings page, make the Size field a required field with the default value of Large. Under Attribute field settings, make sure Enable this field to function as an attribute field on Add to Cart forms is checked and use the radio buttons widget. Save the new field:

In the top right-hand corner, click on MANAGE DISPLAY. Underneath this tab are the currently active build modes. You may have just the default mode or you may have several build modes. At the bottom, there's an item called Layout for pizza in default. This panel controls which build modes you plan to customize:

The second vertical tab controls the layout for the build mode you are currently editing. The default build mode will be used for any display that is not customized:

Starting with the default build mode, select Three column stacked – equal width under the Select a layout section and click on Save. The presentation area should now have five regions, Header, Left, Middle, Right, and Footer. Drag the Product SKU to the Left region, Title to the Middle region, and Price to the Right region. Drag Size and Toppings to the Footer region as shown in the following screenshot, and save the display settings:

Do this for each active build mode. You can worry about further customizations later.

What just happened?

After the modules are installed and enabled, the first thing we did was define a product type. Before you create a node, you have to create a content type. This is the same concept. The product type serves as the prototype for a series of products with similar features. In this case, we basically have two features: Size and Toppings. We created the size and topping options in the product type. We set up the Display Suite settings for our new product type making sure that we display the size and toppings attributes.

Time for action – creating a product

Now, we need to create a product to be able to show the product on the frontend:

Navigate to Store | Products | Add product | Create Pizza.

Give the new product the following values then click on Save product, as shown in the screenshot:

Fields

Values

Product SKU

PIZ

Title

Pizza

Status

Active

Size

Large

Toppings

Cheese Only

Navigate to Store | Configuration | Line item types | Add line item type. Name the new line item type Pizza, check the This is a Product-type Line Item checkbox, and change the Add form submit value to Add to order. Click on Save line item type and then click on Manage fields.

Under the Add an existing field section, click on the Select an existing field pulldown menu and select field_size. Add the label Size and the form widget as Check boxes/radio buttons, then click on Save. Make this field required with a default value as Large. Check the Add to cart form settings checkbox. It can have the value as 1, and the allowed values should be filled in from the Product type listing. They should be the same as in step 4 in the Time for action – the one true theme section. Save the field.

Under Add an existing field section, click on the Select an existing field pull-down menu and select Toppings. Add the label as Toppings and the form widget as Check boxes/radio buttons then click on Save. Make this field as required with a default value of Cheese Only. Check the Add to cart form checkbox. It can have unlimited values and the allowed values should be filled in from the Product type listing. They should be the same as in step 6 in the Time for action – the one true theme section. Save the field.

Navigate to Structure | Content Types | Pizza | Manage fields. Add a new field with the label Product reference and a machine name of field_product_ref of the type Product Reference using the Autocomplete text field widget. On the settings page check the Render fields from the referenced Products when viewing this entity checkbox. Save settings for the new field:

Click on the Manage display tab of the Pizza content type. Using the handlebars beside the fields, replicate the same build mode settings and layout from steps 9 to 11 from the Time for action – the one true theme section—Three column stacked, with Toppings and Size in the Footer region. Once you've moved the Product Reference up, for Format, choose Add to Cart form. Move the old pricing fields to the Disabled section. Our product pricing will replace them:

Click on the line labeled Product Reference. On the select menu labeled Add to Cart line item type, select Pizza, and then click on Update:

Navigate to Admin | Content and filter the list so that you see only items of the Pizza type. Edit the Each topping node and under Publishing options, uncheck the Published checkbox. Save the node.

Edit the Cheese Pizza node. Delete the values out of the Price field and, in the Product Reference field, begin entering Pizza. The auto-complete feature will finish your typing with the Pizza product you created in Steps 13 and 14 in the earlier exercise. Add the following line to the body of the node:

Each toping: add $1.35/$1.65/$1.90 for SM/MD/LG

Save the node's display settings.

Hop over to your text editor and open the sites/all/themes/dpk/css/ styles.css file. Add the following lines:

Navigate to the Menu page, and your Pizza section should now look similar to the following screenshot:

What just happened?

We created a product for the type, Pizza. The Pizza product's default size is Large with Cheese Only as the default topping.

Once we have the product type and the product, we then created the cart line item. This storage bucket holds user-chosen products once they are added to the cart. We created a customized line item just for pizza that will hold the toppings and size that the user has chosen.

Now that we have these three, we need to connect the behind-the-scenes product with the node system where Drupal displays the bulk of its content. We do that through the Product Reference field. We added a Product Reference field to our content objects that show up on our Menu page, in this case, Cheese Pizza. We adjusted the Display Suite settings for our Pizza node and unpublished the node that explains the pricing structure for extra toppings. Once we have Display Suite set up correctly and the product's backend connected to the node frontend, we are able to see the Add to Cart form with all the toppings and sizes. Now that we have the basics of how to create cart items, let's work out some strategies for implementing the mockups.

Have a go hero – adding a PayPal payment option

Add a PayPal payment option to the checkout process. When the checkout process is finished, add an e-mail to both the customer and the correct franchise that is responsible for delivery.

A room with a viewport

Since their earliest version, mobile browsers have been able to do something desktop browsers cannot and that was scaling the screen. They've had to do this because screen real estate on handhelds is at a premium. Before the iPhone perfected the pinch to zoom, you could use keys on Nokia and Blackberry browsers to zoom into and out of a rendered HTML screen. Most mobile browsers assume that standard HTML documents are meant to have a width of 980 pixels. Fortunately, you can control the width of the rendered screen with a <meta> tag. You can set the viewport scale at the optimum width for whatever screen on which its being viewed. I usually set the viewport at the optimum for the 320 by 480 pixels screen and use JavaScript to change the settings if the screen is larger.

Let's take a look at the settings in the html.tpl.php file:

We can use JavaScript to adjust this setting when the screen calls for it.

Time for action – setting the viewport with JavaScript

Edit the sites/all/themes/dpk/js/global.js file. Add the following lines:

What just happened?

So the first item sets the <meta> tag, viewport with settings that are complimentary to an iPad or large-format tablet. We set the width to 760 which will make the page visible on the tablet and is squarely in the center of our middle width. If the screen size is less than 480 pixels, the JavaScript behavior trades out the viewport setting for the one that sets the width of the viewport at the device's width.

Time for action – advanced media queries for tablets

Rename sites/all/themes/dpk/css/styles.css to sites/all/themes/ dpk/css/global.css. As shown in the following screenshot, add three more files in that folder—global_480.css, global_800.css, and global_1024.css:

Edit the file, sites/all/themes/dpk/dpk.info. Add the highlighted lines in the following code snippet:

Open a WebKit-based browser or Firefox and visit http://dpk.local/menu. Add a menu item to the cart. If you size the window up and down, the layout now responds to size change, by making both the header and footer logos smaller and in fixed position.

What just happened?

This is where the importance of semantic markup comes into play. Notice how the logo is not an image, it's an <h1> and <a> tag with a background image, width, and height applied by CSS rule. Well, because there's no hard image on the page as we size up and down we can swap out the width and height on the <a> tag. Tricks such as these are the basis of responsive design. We use CSS rules to describe the three base layouts of our site—phone, tablet, and desktop.

Summary

In this article, we examined touch events and went over the differences between touch events and mouse-click events. We added touch events to our jQuery cycle on the home page so that the user can advance the slideshow with their fingers. We took a second look at adaptive web page designs and began the process of adapting a design for three layouts. We added CSS for each layout and began the process of defining the look and feel of each of the three use cases.

Alerts & Offers

Series & Level

We understand your time is important. Uniquely amongst the major publishers, we seek to develop and publish the broadest range of learning and information products on each technology. Every Packt product delivers a specific learning pathway, broadly defined by the Series type. This structured approach enables you to select the pathway which best suits your knowledge level, learning style and task objectives.

Learning

As a new user, these step-by-step tutorial guides will give you all the practical skills necessary to become competent and efficient.

Beginner's Guide

Friendly, informal tutorials that provide a practical introduction using examples, activities, and challenges.

Essentials

Fast paced, concentrated introductions showing the quickest way to put the tool to work in the real world.

Cookbook

A collection of practical self-contained recipes that all users of the technology will find useful for building more powerful and reliable systems.

Blueprints

Guides you through the most common types of project you'll encounter, giving you end-to-end guidance on how to build your specific solution quickly and reliably.

Mastering

Take your skills to the next level with advanced tutorials that will give you confidence to master the tool's most powerful features.

Starting

Accessible to readers adopting the topic, these titles get you into the tool or technology so that you can become an effective user.

Progressing

Building on core skills you already have, these titles share solutions and expertise so you become a highly productive power user.