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:
- We can leave out the format, leaving the user to utilize
the device’s options for changing to number/symbol input as required. - We can have the user round to the nearest dollar and
enter only whole numbers. - We can preformat the data entry, specifying that one of
the characters is a decimal point. For example:format="NNN.NN".
- We can have the user enter the whole number and decimal
amounts separately.
Each of these options has a downside:
- 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. - Rounding to the nearest dollar won’t be exact and won’t
allow us to display a total (amount + tip). - 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. - 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; wehave 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/> = $(amt10)<br/> 15% -$(tip15)<br/> = $(amt15)<br/> 20% -$(tip20)<br/> = $(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 sschafer@synergy-tech.com.
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.
# # #