1. Developing webOS Apps
CS96SI
UI Components and Services
Fred Patton
Editor-in-chief, Palm Developer Portal
Thursday, April 29, 2010 1
2. What are UI Components?
Common visual/interactive
elements.
Basic designs provided, but
customization is allowed.
Implemented through “widget
assistants” in .js files.
Behavior encapsulated in
widget_controller.js.
Thursday, April 29, 2010 2
3. Why Use UI Components?
Common components aid user familiarity - no
guessing about functionality.
Written documentation is an admission of
failure!
Re-use of existing components greatly
speeds development time.
Powerful functionality built-in.
Thursday, April 29, 2010 3
For example, if you were developing your app as a straight PDK app, you’d need to re-invent the buttons, text
boxes, lists.
The List widget encapsulates dragging and dropping, deleting from the list, adding to the list, physics based
scrolling models, etc.
I’m not crazy about going nuts with customization. Written documentation is an admission of failure!
4. Where are they?
Mojo.Widget - Primary source of UI
components. Usually declared in the scene
view.
Mojo.FilePicker - Allows navigation to, and
selection of files. Not declared in the scene
view.
Mojo.Menu - not declared in the scene view.
Works above the scene.
Thursday, April 29, 2010 4
The Style Matters and UIWidgets examples come with the SDK. They have lots of examples of using and
customizing widgets.
5. The Humble Button
<div x-mojo-element="Button" id="button1"></div>
this.attributes = {
};
this.model = {
};
this.controller.setupWidget("button1", this.attributes,
this.model);
If we do nothing else, we’ll at least get a
button
Thursday, April 29, 2010 5
We’re going to talk about the button for a little while, because it’s a good introduction to the widget framework,
use and customization. We’ll then talk about lists and menus.
This is all that’s required to instantiate a button. You need a bit of HTML in your scene’s HTML file, and a bit of
setup code in the assistant’s “setup” function.
6. Let’s add a label
this.attributes = {
};
this.model = {
buttonLabel: “Hello”
};
this.controller.setupWidget("button1", this.attributes,
this.model);
Thursday, April 29, 2010 6
You could also put the text in the <div>.
7. Activity Button
this.controller.setupWidget('button-1',
this.atts = {
type: Mojo.Widget.activityButton
},
this.model = {
buttonLabel: 'Press me',
buttonClass: 'affirmative',
disabled: false
});
activityButton allows for a spinner
affirmative buttonClass makes it green
Thursday, April 29, 2010 7
Now, why would you want the button to be green? Well, by itself, you probably wouldn’t. But in combination with a
(next slide)....
8. Negative buttonClass
this.controller.setupWidget('button-1',
this.atts = {
type: Mojo.Widget.activityButton
},
this.model = {
buttonLabel: 'Press me',
buttonClass: 'negative',
disabled: false
}
);
Button text is almost unnecessary now...
Thursday, April 29, 2010 8
...negative button, you can give the user a clear choice between doing something constructive and something
destructive. Text is of course necessary, because you never know when you have a color-blind user.
9. Changing the Model
...
this.buttonModel.buttonLabel = "Goodbye";
this.controller.modelChanged(this.buttonModel);
...
modelChanged alerts the program that it
needs to update the widget(s) associated
with the model.
Thursday, April 29, 2010 9
Note that if you have multiple widgets associated with the model, then ALL of those widgets will be updated.
10. CSS by Class
.myclass .palm-button {
-webkit-border-image: url(../images/button-blue-
up.png) 0 16 0 16 stretch stretch; }
.myclass .palm-button.selected {
-webkit-border-image: url(../images/button-blue-
down.png) 0 16 0 16 stretch stretch; }
<div x-mojo-element="Button" id="fooButton" class="myclass">Press
Me</div>
myclass inherits from .palm-button, but gets
its image overwritten.
Thursday, April 29, 2010 10
See http://www.lrbabe.com/sdoms/borderImage/index.html for a nice write-up on border images.
11. Visualizing Border Image
.stylishContent {
display: inline-block;
border-width: 27px 27px 27px 27px;
border-image: url(http://www.w3.org/TR/css3-background/border.png)
27 27 27 27;
}
<div class="stylishContent">Some stylish content</div>
Check out Kevin Decker’s article:
http://www.incaseofstairs.com/2010/04/border-image-generator/
Thursday, April 29, 2010 11
The border image itself is divided into zones by use of the offset parameters. The various parts of the image are
stretched to fit.
12. List Widget
One of the most common
widgets, but also most
powerful.
Many applications will use the
list in some form or other.
Scrolling follows a built-in
rubber band physics model.
Very customizable.
Thursday, April 29, 2010 12
13. List Components
List <div> - Specifies placement of the list.
Lives in your scene HTML.
List container - Template file for the list as a
whole. Lives in its own HTML file
List item template - describes what each row
will look like. Lives in its own HTML file.
Thursday, April 29, 2010 13
14. List <div>
<div id='MyListContainer'>
<div id="my_list" x-mojo-element="List" >
</div>
</div>
Goes in your scene HTML
Thursday, April 29, 2010 14
15. List Container
<div class="palm-group">
<div class="palm-group-title">
#{-listTitle}
</div>
<div class="palm-list">
#{-listElements}
</div>
</div>
For this example, file is called
“listcontainer.html”
There’s going to be a title on this list,
followed by some number of list elements.
Thursday, April 29, 2010 15
16. List Item Template
<div class="palm-row">
#{-word}
</div>
For this example, file is called “listitem.html”.
Minimalist HTML for an individual row. (More
complicated one coming up.)
Your code will assign data to “word” in the
JavaScript
“-” escapes any HTML
Thursday, April 29, 2010 16
Escaping HTML - for example, if you reply with "Joe > Bob!" and don't “-” it, the “>” would be converted to
> which may be bad.... so you have to really think about what you are doing with the data etc.
17. List Instantiation
this.listModel = {listTitle:$L(“My List”), items:this.items};
// Set up the attributes & model for the List widget:
this.controller.setupWidget('my_list', {
itemTemplate:'lists/list/listitem',
listTemplate:'lists/list/listcontainer'},
this.listModel
);
Note the references to “listTitle” and
“listcontainer”.
“items” will be populated elsewhere, but is an
array of objects.
Thursday, April 29, 2010 17
18. Setting up “items”
items.push({word: “Scintillating”};
this.listModel.items = items;
this.controller.modelChanged(this.listModel);
Push data into an array
Assign the array to the list model
Tell the controller that the model has
changed
List will be updated
Thursday, April 29, 2010 18
19. Complex List Template
<div class="palm-row">
<table border="0" cellpadding="0" cellspacing="0">
<tr>
<td width="75px"><img src=#{image} height=48 cell-padding="2px"
align="center"></td>
<td>#{title}<br />#{price}</td>
</tr>
</table>
</div>
“image” gets defined
elsewhere as a URL.
Thursday, April 29, 2010 19
What’s happening here? Each row in the list is going to be comprised of a little table with two columns. The first
column has an image in it, and the second colum has title and price info. Price is on the second line.
21. App Menu
var appMenuModel = {
items: [Mojo.Menu.editItem, {
label: $L("Preferences & Accounts"),
command: Mojo.Menu.prefsCmd
},...
{
label: $L("Help"),
command: Mojo.Menu.helpCmd
}]
};
this.controller.setupWidget(Mojo.Menu.appMenu, {
omitDefaultItems: true
},
appMenuModel);
Basic setup instantiation - no HTML needed.
Need a command handler (see sample)
Thursday, April 29, 2010 21
If your app is going to have more than one scene, you should put the command handler in the stage assistant,
then instantiate the menu in each scene.
22. Global Stylesheets
All the global style sheets are available in
the SDK:
share/refcode/framework/[xxx]/stylesheets
Shows what styles are available to override.
Thursday, April 29, 2010 22
23. Services
Provide access to core applications, hardware,
and low level system functions
Application services
System services
Cloud Services
Thursday, April 29, 2010 23
Application services provide access to core applications, so you can launch a URL through the browser, play audio
or video, launch the camera or contact apps, etc.
System services provide access to hardware-based services and other low-level functions, like location and the
accelerometer.
Cloud services provide access to web-based services like Extensible Messaging and Presence Protocol (XMPP)
messaging.
24. Some examples
Accelerometer
Alarms
GPS
System sounds
Email
Thursday, April 29, 2010 24
Accelerometer - gets X, Y, and Z g-loads at up to 30Hz. Also senses orientation.
Alarms - Set one to get an event to fire later. Very useful in applications that spend a lot of time idle.
GPS - Get current position data, or track position over time.
Email - Like a lot of app launchers; launch the app, but populate fields with a specific value. So, you could bring
up a new email with the to, from, subject, and body fields already filled in.
25. System Sounds
this.controller.serviceRequest("palm://com.palm.audio/systemsounds",
{
method: "playFeedback",
parameters: {
name: "dtmf_2"
}
}
);
Plays the DTMF tone for the number 2.
System requests each have their own
identifier. (Not really a URL.)
Thursday, April 29, 2010 25
I’m going to show a couple of simple code examples to give you the flavor of service calls, and then we’ll get into
a live demo of a service.
26. Send an email
this.controller.serviceRequest("palm://com.palm.applicationManager", {
method: "open",
parameters: {
id: "com.palm.app.email",
params: {
summary: "Subject line",
text: "This is the text of the email.",
recipients: [{
type: "email",
role: 1, //1:to, 2:cc, 3:bcc
value: "mailto:fred@palm.com",
contactDisplay: "Fred Patton" //Required!
}]
}
}
});
Thursday, April 29, 2010 26
Here we’re using the URI to launch the email application. We’re just populating the To: address. We could populate
the message body too, but it gets messy. Code needs to be readable.
Note this uses the Application Manager to launch email. You can do something similar for apps like Photo, Video.
27. Accelerometer setup
if (this.controller.stageController.setWindowOrientation) {
this.controller.stageController.setWindowOrientation("free");
this.controller.stageController.setWindowProperties("fastAccelerometer");
}
this.handleOrientation = this.handleOrientation.bindAsEventListener(this);
Mojo.Event.listen(document, 'orientationchange', this.handleOrientation);
this.handleAcceleration = this.handleAcceleration.bindAsEventListener(this);
Mojo.Event.listen(document, 'acceleration', this.handleAcceleration);
Note “bindAsEventListener” - Makes sure an
event is passed. Keeps a reference to the
object.
Listening for particular events.
Thursday, April 29, 2010 27
Looking at the HTML, you’ll see that I’ve put in some dummy text. Strictly speaking, this isn’t necessary, but like
initializing variables, it makes me feel better. I prefer to see something on the screen. That way, if something goes
wrong, I’ll at least know whether the HTML is at fault or not, depending on whether it displays anything.
Note the Mojo.Event.listen. We’re listening for two events simultaneously: orientation change and acceleration.
Any time either happens, the bound callback will be called. These events happen 30 times per second.
28. Accelerometer Response
MainAssistant.prototype.handleAcceleration = function(event){
this.controller.get("accx").update("X = " + event.accelX);
this.controller.get("accy").update("Y = " + event.accelY);
this.controller.get("accz").update("Z = " + event.accelZ);
}
MainAssistant.prototype.handleOrientation = function(event){
var position = ["Flat, face up","Flat, face down", "Upright", "Upside
Down", "Pointed left", "Pointed right"]
this.controller.get("position").update("Current orientation is: " +
position[event.position]);
this.controller.get("roll").update("Roll: " + event.roll + " degrees");
this.controller.get("pitch").update("Pitch: " + event.pitch + " degrees");
}
Thursday, April 29, 2010 28
Note that we’re receiving an event object. The contents of that object depend on the event being fired, so we have
to be careful what we bind to. An acceleration event contains values for X, Y, and Z acceleration.
29. Wrap-up
Any questions?
Thursday, April 29, 2010 29