Mobile Learning WML - Building Gadgets

Learning WML – Building Gadgets

It is easy to fall into the trap of looking only for killer
applications to deploy via mobile devices. Integration with other services,
online databases, etc. are all worthy applications to code and offer via
wireless connections. However, you shouldn’t overlook the smaller,
single-function applications that users might find useful or even

necessary.

From Merriam-Webster’s
Online Collegiate. Dictionary
(
http://www.webster.com/
):

Gadget – an often small mechanical or electronic device with
a practical use but often thought of as a novelty

My current phone has several gadgets—a calculator, a
calendar, etc. Each of these makes the phone a bit more useful since I carry

it with me all the time. True, it doesn’t replace a PDA or other device loaded

with such functionality and utility, but I find having these features a great
addition to the phone.

However, not all phones have these gadgets built in. This article will

create one such gadget: a tip calculator. Along the way we will explore

different ways to accept user input as well as some variable-type artifacts of

WMLScript.

Note: Creating online gadgets presents a tradeoff for users; although they

gain the utility of the gadget, they must use airtime/online time to use it.

Keep this in mind when creating such applications and strive to keep their

uses simple and short.

Building a Tip Calculator

A few people I know carry a "tip card" with them to easily

compute the correct amount of their tip to leave at a restaurant. This card

gives whole dollar amounts and the representative percentage thereof, in 10%,

15%, and 20% values. A quick-and-dirty gadget can be implemented via WML and

WMLScript to accomplish the same thing.

Description of Project

This project is very straightforward-—accept a dollar amount and

display 10, 15, and 20 percent of the value entered. As an added benefit,
the application should display the total of the dollar amount and tip

amount.

Data Entry

To enter the amount, we can simply use a WML INPUT tag. For example, the

following code snippet would do:

<card>
  <p>
  <input
name="amount"/>
  </p>
</card>

To make the data input easier for the user, we could add a format parameter

to the INPUT tag to specify that the input should be numeric:

  <input name="amount" format="*N">

However, this format specification doesn’t allow for symbols, namely a

decimal point. The available format codes for the format parameters do not

include a format with both numbers and symbols, but without letters. So we can

choose from several options for getting the dollar amount from the user:

  1. We can leave out the format, leaving the user to utilize
    the device’s options for changing to number/symbol input as required.
  2. We can have the user round to the nearest dollar and
    enter only whole numbers.
  3. We can preformat the data entry, specifying that one of
    the characters is a decimal point. For example:

    format="NNN.NN".

  4. We can have the user enter the whole number and decimal
    amounts separately.

Each of these options has a downside:

  1. If the amount isn’t easy to enter, the user won’t be apt
    to use the gadget. (Also consider the online time for using the gadget.) Most
    devices don’t exactly make it easy to switch between numbers and symbols.
  2. Rounding to the nearest dollar won’t be exact and won’t
    allow us to display a total (amount + tip).
  3. Specifying an exact mask requires the user to follow the
    mask exactly, entering more data than sometimes required. For example, in our
    example mask ("NNN.NN"), the user must preface any amount under $100
    with a zero (e.g., "090.00") to fit the mask.
  4. Entering two separate amounts, one for the whole number
    portion and the other for the decimal, isn’t intuitive.

For this example, we will use the fourth option, entering
two numbers-one for the whole portion and one for the decimal:

  <p>
    <!-- Get whole and decimal amounts separately
      to aid user input -->
    Enter amount:<br/>
    <input name="checkamt" format="*N"/><br/>
    .<br/>
    <input name="checkdec" format="*N"/>
  </p>

With the code above, the user enters the whole amount,
presses ACCEPT, enters the decimal amount, and presses ACCEPT again. Although
not intuitive, the data input process is very streamlined.

The input screen. Note how the decimal is displayed (on the
left side, between the two text boxes) to help the user understand the

screen.

Image is courtesy Openwave Systems Inc. (Openwave, the
Openwave logo, Openwave SDK, Openwave SDK Universal Edition, Openwave SDK WAP
Edition are trademarks of Openwave Systems Inc. All rights
reserved.)

Combining the Input

Our approach for accepting input has one disadvantage; we
have to combine the input to obtain the full amount. This only takes a simple
WMLScript that gets the amounts from the WML code, combines them, and returns
the amount to the script.

Consider the following:

WML

<?xml version="1.0"?>
<!DOCTYPE wml PUBLIC "-//WAPFORUM//DTD WML 1.1//EN"
  "http://www.wapforum.org/DTD/wml_1.1.xml">
<wml>
  <card id="input">
    <do type="accept">
      <go href="test.wmls#calc()"/>
    </do>
    <p>
    Enter amount of check in dollars and cents:<br/>
    <input name="num" format="*N"/><br/>
    .<br/>
    <input name="dec" format="*N"/>
    </p>
  </card>
 
  <card id="result">
    <p>
    Result is: $(result)
    </p>
  </card>
  
</wml>

WMLScript

extern function calc() {
  
var num = WMLBrowser.getVar("num");
var dec = WMLBrowser.getVar("dec");
var result;
  
dec = dec / Float.pow(10,String.length(dec));
result = num + dec;
  
WMLBrowser.setVar("result",result);
WMLBrowser.go("junk.wml#result");
}

We can reduce the amount of computation necessary to derive
the total by using the dynamic nature of variable typing in WMLScript.
Essentially, if we force WMLScript to treat the variables as strings, creating
the total is as easy as this:

result = num + "." + dec;

Note: If no decimal amount was entered (variable
"dec" is empty), the result variable will have a trailing period

(.).

Displaying the Results

Now that we have the amount, a handful of additional
computations will give us the results to display for the user. We need to
figure 10%, 15%, and 20% of the amount and total each percentage with the
amount:

// Add whole and decimal to get check amount
check = check + "." + dec;
  
// Calculate tip at 10%, 15%, 20% and totals for each amt
tip10 = check * .1;
tip15 = check * .15;
tip20 = check * .20;
amt10 = Lang.parseFloat(check) + Lang.parseFloat(tip10);
amt15 = Lang.parseFloat(check) + Lang.parseFloat(tip15);
amt20 = Lang.parseFloat(check) + Lang.parseFloat(tip20);

Note: I’ve replaced the generic variable name "num"
with the variable name "check" above.

Notice the use of the Lang.parseFloat function. This helps
ensure that WMLScript treats the amounts as floating-point numbers instead of
strings. Otherwise, given these two numbers:

  check = 17.35
  tip10 = 1.735

we end up with this:

  amt10 = 17.351.735

which is the concatenation of the variables as strings,
instead of their addition as floating points.

Finally, the WMLScript needs to push the variable values to
WML and call a display card:

// Push values to WML
WMLBrowser.setVar("check",check);
WMLBrowser.setVar("tip10",tip10);
WMLBrowser.setVar("amt10",amt10);
WMLBrowser.setVar("tip15",tip15);
WMLBrowser.setVar("amt15",amt15);
WMLBrowser.setVar("tip20",tip20);
WMLBrowser.setVar("amt20",amt20);
  
// Call total card
WMLBrowser.go("tipchart.wml#tipamount");
}

The Completed Code

tipchart.wml

<?xml version="1.0"?>
<!DOCTYPE wml PUBLIC "-//WAPFORUM//DTD WML 1.1//EN"
"http://www.wapforum.org/DTD/wml_1.1.xml">
  
<wml>
  
  <!-- Get amount of check and pass to calculator -->
  <card id="checkamount" title="TipCalculator">
  <onevent type="onenterforward">
    <!-- Clear previous values -->
    <refresh>
      <setvar name="checkamt" value=""/>
      <setvar name="checkdec" value=""/>
    </refresh>
  </onevent>
  
  <!-- Call calculator when amounts have been entered -->
  <do type="accept">
    <go ref="tipchart.wmls#calctip()"/>
  </do>
  <p>
    <!-- Get whole and decimal amounts separately
      to aid user input -->

    Enter amount of check in dollars and cents:<br/>
    <input name="checkamt" format="*N"/><br/>
    .<br/>
    <input name="checkdec" format="*N"/>
  </p>
  </card>
  
  <!-- Display tip amounts and totals -->
  <card id="tipamount">
  <do type="accept">
    <go href="#checkamount"/>
  </do>
  <p> 
    Check Amount: $(check)<br/>
    10% -$(tip10)<br/>
&nbsp;&nbsp;= $(amt10)<br/>
    15% -$(tip15)<br/>
&nbsp;&nbsp;= $(amt15)<br/>
    20% -$(tip20)<br/>
&nbsp;&nbsp;= $(amt20)<br/>
  </p>
  </card>
  
</wml>

tipchart.wmls

// Tip Calculator script
  
// calctip - calculate tip amount from values entered
extern function calctip() {
  
// Get check amount (and decimal portion) from WML
var check = WMLBrowser.getVar("checkamt");
var dec = WMLBrowser.getVar("checkdec");
  
// Init tip and total vars
var tip10, tip15, tip20, amt10, amt15, amt20 = 0;
  
// Add whole and decimal to get check amount
check = check + "." + dec;
  
// Calculate tip at 10%, 15%, 20% and totals for each amt
tip10 = check * .1;
tip15 = check * .15;
tip20 = check * .20;
amt10 = Lang.parseFloat(check) + Lang.parseFloat(tip10);
amt15 = Lang.parseFloat(check) + Lang.parseFloat(tip15);
amt20 = Lang.parseFloat(check) + Lang.parseFloat(tip20);
  
// Push values to WML
WMLBrowser.setVar("check",check);
WMLBrowser.setVar("tip10",tip10);
WMLBrowser.setVar("amt10",amt10);
WMLBrowser.setVar("tip15",tip15);
WMLBrowser.setVar("amt15",amt15);
WMLBrowser.setVar("tip20",tip20);
WMLBrowser.setVar("amt20",amt20);
  
// Call total card
WMLBrowser.go("tipchart.wml#tipamount");
}

The user enters the amount of the check. . .

And receives three escalating tip amounts and related
totals.

Images are courtesy Openwave Systems Inc. (Openwave, the

Openwave logo, Openwave SDK, Openwave SDK Universal Edition, Openwave SDK WAP

Edition are trademarks of Openwave Systems Inc. All rights

reserved.)

Note the addition of an initialization <REFRESH> event
on the "checkamount" card. This ensures that the variables are
cleared whenever this card is called, whether the first time through the code
or via the "results" card.

Room for Improvement

Of course, there’s always room for improvement. In this
case, rounding the tip amounts to the nearest cent would be handy. This can’t
be accomplished directly with the Float.round WMLScript function, which only
rounds to the nearest integer. The round function can be used if the decimal

is moved, round is used, and then the decimal is moved back. (multiply the

amount by 100, add .5, round to nearest integer, divide by 100)

What Do You Want from WML?

I’m interested in hearing what you need/want to do with WML.
I’ll use some of the more challenging or common ideas in upcoming articles.
Send your ideas to the address below.

About the Author

Steve Schafer is chief operating officer of Progeny Linux Systems, a

Linux-based consulting company in Indianapolis, Indiana. He has written

several technical books and articles and can be reached at [email protected].


This series of articles describes how to provide Web
content to mobile devices through WML (Wireless Markup Language). This article
covers creating small programs extending the functionality of mobile

devices.

Note: These articles cover WML and WMLScript version 1.1,
which are supported by the majority of mobile devices in use today. The
articles assume a working knowledge of HTML and general Web technologies, and
further assume that you have read the previous article(s) in this series.

# # #

Latest Posts

Related Stories