Saturday, August 6, 2011

We All Need a Little Support

Last month, I alluded to a future post that would show the usefulness of document.getElementById('element').value. I'm delivering on that promise now.

This post explores a few different techniques within webOS and PhoneGap to create a highly functional application. To illustrate the idea, we'll make a support form.

Set up a standard HTML page with the usual PhoneGap reference. We'll write the structure of the form in the body of the document.
<h2 align="center">Support Request</h2>
<h3 align="center">Help us help you!</h3>
<p align="center">Please fill out the below form to contact support.</p>
<form align="center" name="oForm">
<table>
<tbody>
<tr><td align="right">Name:</td>
<td><input type="text" name="name" id="name" /></td></tr>
<tr><td align="right">E-mail:</td>
<td><input type="text" name="add" id="add" /></td></tr>
<tr><td align="right">Problem:</td>
<td><textarea rows="5" cols="22" name="problem" id="problem"></textarea></td></tr>
</tbody>
</table>
<input type="button" onclick="formSubmit()" value="Submit form" align="center"/>
</form>
There are a couple of important parts to note. Each of the input fields has its own id value to identify it, and the form triggers formSubmit() on the button click. The formSubmit function is where the fun twiddly bits go.
function formSubmit(){
var datestamp=new Date();
var title= "Support Request from "+ document.getElementById('name').value;
var text_cont="Name: "+document.getElementById('name').value+"<br/>E-mail Address: " +document.getElementById('add').value+"<br />Timestamp: "+datestamp +"<br />Problem: "+document.getElementById('problem').value;
try { this.service = navigator.service.Request('palm://com.palm.applicationManager', { method: 'launch', parameters: { id: "com.palm.app.email", params: { summary: title, text: text_cont, recipients: [{
type:"email",
role:1,
value:"johnsmith@example.com",
contactDisplay:"John Smith" }] } } }); }
catch(ex) {console.log("error");}
}
The first few variables are strings that construct various parts of the message. You can see at that point that we're pulling the form field contents using document.getElementById('element').value. We then take those variables and use navigator.service.Request to launch the e-mail app and pass the parameters to it.

Now, let's put it to the test. Superman is having some connectivity issues.


Superman then submits the form, which composes a structured and date stamped email to system administrator John Smith. (What, were you expecting Lex Luthor to be the Sysadmin? He's busy.)


You can see the power and flexibility behind this method, as it allows you to act on any form input from a user such as radio, dropdown lists, and more. The ability to pass those parameters to a composed email is a useful trick as well. This example is posted in a github gist, please feel free to use and distribute the code as you see fit.

Tuesday, July 26, 2011

This is Why You RTFM

A more accurate title might be RTFF (Read the ****ing Framework), but that doesn't have quite the same ring to it.

For a while now, I've been idly wondering how to make webOS PhoneGap apps rotate with the device orientation. I knew that there was a way to set orientation via a PhoneGap function, but I didn't bother investigating since it wasn't needed at the time. Until today. I started wondering about possible solutions, perhaps by adding event listeners to detect the orientation and set the corresponding direction.

It turns out that the answer is in the framework, underneath the orientation class.

/*
 * Manually sets the orientation of the application window.
 * 'up', 'down', 'left' or 'right' used to specify fixed window orientation
 * 'free' WebOS will change the window orientation to match the device orientation
 * @param {String} orientation
 * Example:
 *        navigator.orientation.setOrientation('up');
 */

Yes, it really is as easy as including "navigator.orientation.setOrientation('free');".

Yes, I felt twice as dumb after realizing that the reference was part of Herm's example code.

Yes, I will RTFM from now on.

Sunday, July 17, 2011

Tips from the Twitterverse

I haven't forgotten about webOScapades. Oh, not at all. I have a few new posts coming soon. Today, I'll dip into the lovely mess of Twitter for some PhoneGap tips.

The first tip comes from Herm Wong at Nitobi, the gentleman responsible for the updates to PG-webOS. It stems from two questions that posed to him: how do you programmatically close the card that you're currently in, and how do you close the parent of the card that you've opened? He's compiled the answers into a comprehensive post on his blog, which also includes the parameter passing tricks. Window.close() and other functions are part of the Javascript Window object, so if you find other window functions that work well with PhoneGap/webOS, please post about it in the comments!

The second tip is from Markus Leutwyler at HP. If you've gotten your hands on one of those shiny new HP Touchpads, the inertial scrolling examples that I posted about work very well. Just add "uiRevision" : "2" to your appinfo.json file. The end result is a full-screen app with code that works on webOS 1.x, 2.x, and 3.x at the same time. In my opinion, that's a pretty good answer to the Mojo/Enyo debate.

One final bit of news: PhoneGap 1.0.0 is on its way. Woohoo! It includes support for touch events, which has been documented by Herm on his blog.

Saturday, July 2, 2011

Passing Parameters to a New Card in PhoneGap

Here's a neat trick to whet your PhoneGappetites. As I've said before, Herm Wong's excellent tutorial series on using PhoneGap with webOS is a great place to get started with development. I'm going to concentrate on a particular post of his, how to use the New Card API in PhoneGap

To launch a new card, just use the form of "navigator.window.newCard(url, html);". While this invocation is both simple and powerful, it's also somewhat lacking. If you open a new card using the url parameter, it  just calls that page statically. Using the optional html field to pass code gives you some options of interacting with the new card, but isn't a reusable method and your code becomes needlessly messy. The most successful apps live and breathe on passing dynamic data. What can you do to get there?

The solution came from this post on the HTML Forums. Simply pass parameters via the URL, the same way that you would for other web languages like PHP. It takes the form of file.html?firstname=Keanu&lastname=Reeves. 

No SEO trickery going on here. Nope.

Here's a PhoneGap-ready example of the code. Put these two files in your webos/framework directory.

index.html
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>PhoneGap WebOS</title>
    <script type="text/javascript" src="phonegap.js"></script> 
    <script type="text/javascript">
         function onLoad() {
            navigator.device.deviceReady();
        }
    </script>
</head>
<body onload="onLoad();">                                         
    <p><input type="button" value="Launch a new card" onclick="navigator.window.newCard('passing.html?firstname=Keanu&lastname=Reeves');"></p>                                                                      
</body>
</html>

passing.html
<html>
<head>
<title>Page 2</title>
<script type="text/javascript" src="phonegap.js"></script>  
<script type="text/javascript">
    var query = location.href.substring((location.href.indexOf('?')+1), location.href.length);
    if(location.href.indexOf('?') < 0) query = '';
    querysplit = query.split('&');
    query = new Array();

    for(var i = 0; i < querysplit.length; i++){
        var namevalue = querysplit[i].split('=');
        namevalue[1] = namevalue[1].replace(/\+/g, ' ');
        query[namevalue[0]] = unescape(namevalue[1]);
    }

    window.onload = function(){
        document.getElementById('firstname').innerHTML = query['firstname'];
    document.getElementById('lastname').innerHTML = query['lastname'];
    }
</script>
</head>
<body>
<h1>Who are you?</h1>
<p>Your name is <span id="firstname"></span> <span id="lastname"></span></p>
</body>
</html>
VoilĂ ! For added fun, try to modify the example to use input from two text fields to pass data to the new card. Not sure how? Here's a hint: Use "document.getElementById('element').value" to access the contents of the form fields. More on that in a coming post.

Thursday, June 30, 2011

Inertial Scrolling on webOS using PhoneGap and iScroll 4

So, let's get down to working with PhoneGap. One of the first things you'll notice when you make a PhoneGap app on webOS is that the page doesn't scroll. Palm has a nice inertial scrolling widget, so what's going on? Well, there's no scrolling widget in stock PhoneGap. If you drag your finger on a page, it'll just highlight the contents. Don't worry. There's an easy way to fix this.

My solution of choice is the iScroll 4 framework by Matteo Spinelli. The beauty of iScroll is that it allows you to scroll within a fixed space, letting you set a header and footer -- perfect for mobile apps. A great starting point is to try out the examples provided with the framework. I've tested both the Simple Scroll and Carousel samples on webOS 2.1 with excellent success. Download the latest iscroll.js file and put it in your webOS/framework PhoneGap folder. If you're using the stock examples in iScroll 4, make sure to include the <script type="text/javascript" src="phonegap.js"> </script> reference in the head of your code, and <script type="text/javascript"> navigator.device.deviceReady(); </script> in the body.

Now, iScroll 4 likes to scroll lists. If you want a single page scrolled and are using one of the provided examples as a template, you can simply put the entire contents of your page into one <li>. Just go to the #scroller li style section and remove height:40px.

The framework has quite a bit to offer beyond just scrolling, but I haven't been able to get some of the other functions running just yet. The Pinch/Zoom and Pull to Refresh examples aren't working out of the box on webOS. Really, those would just be icing on a very delicious cake. With the scrolling functionality alone, iScroll 4 is a powerful and much needed option in your programming toolbox.

Sunday, June 26, 2011

webOScapades -- Occasional Adventures in webOS Development

I make no bones about it, I like HP's (nee Palm's) webOS platform. The operating system is beautiful, the community is incredible, and the development process is a charm.

The power of webOS lies in the use of web technologies. You can build a quality app with nothing more than HTML, CSS and JavaScript. Web programmers will be right at home. For webOS 1.x and 2.x, you generally needed to learn an MVC style framework called Mojo. Mojo is old news -- starting with webOS 3.0, the new hotness is Enyo. The Enyo SDK is currently under NDA in the HP Early Access Program, but will be presumably be publicly released in the near future when the HP TouchPad ships on July 1st, 2011.

I'm not walking the Enyo road just yet. Right now, I'm having much more fun playing with PhoneGap, a cross-platform framework that allows you to write HTML/JavaScript apps and author them on multiple platforms. As of version 0.9.5, PhoneGap is Mojo-free. You write just as you would for a standard web page and include a little PhoneGap JS code. The best way to get started would be to download the latest version of PhoneGap (0.9.5.1 at this writing) and delve into Herm Wong's excellent webOS PhoneGap tutorials. His "Getting Started with PhoneGap WebOS 0.9.5" post is a good place for beginners, and includes links to other needed steps.

Becoming a webOS developer couldn't be easier -- or cheaper, for that matter. It's free. As in zero, zip, nada. Just sign up at the HP webOS Developer Portal. Community accounts will give you access to play around with the SDK and post in the forums, but you'll need a Developer account to publish apps in the App Catalog. For that, you need a PayPal account (to get paid) and a business tax id number (to pay the government).

By itself, PhoneGap isn't enough to make a quality webOS app. You need to add the functionality in bits and parts. As I discover more pieces of the puzzle, I'll put together posts and tutorials on the process. This blog will hopefully be an aid to others on the same path.

Ken Schreihofer