
This work is licensed under a Creative Commons Attribution-Noncommercial-Share Alike 3.0 License
This tutorial is intended to give an overview of the development of applications using the MyMobileWeb v4.0 framework.
Table of Contents
In this tutorial we will show some of the most important functionalities provided by MyMobileWeb and how developers get access to such functionalities. We will demonstrate this by developing a (minimalistic) multi-device mobile web portal dedicated to the Spanish National Soccer League ("La Liga").
As usual, the first step to start developing your application is to gather all the requirements that need to be met. Once the requirements are known, the next activity is to design the information architecture of your portal, which will allow to determine the number of pages (presentations in MyMobileWeb jargon) needed and the navigation flow between them. Then, the structural and presentational aspects (style) of pages will be designed. The next step is to create the business logic (Application Operations in MyMobileWeb's terminology) that will give functionality and content to your application. Once you have developed the application, it has to be tested in multiple devices (or emulation environments), making the necessary adjustments and corrections. Finally, the application has to be deployed in a production environment, making it accessible to your Internet users.
The requirements for our Mobile Soccer Portal are simple and concise:
R1: The portal should provide the latest news about "La Liga".
R2: The portal should provide the latest news on a per club basics.
R3: The portal should provide information about the rounds, games, and standings.
R4: The portal should offer a functionality to navigate through club's image galleries.
R5: The portal must provide statistics about the competition, such as the number of Leagues won by the different clubs throughout history.
R6: The portal should offer a functionality for daily news subscription.
R7: The portal contents must be presented both in English and Spanish (internationalization requirement).
Apart from these functional requirements our application has to provide a harmonized user experience for multiple delivery contexts, especially for three "hero devices": Apple's iPhone, Windows Mobile 2005-6 enabled smartphones equipped with a IE Mobile browser and Nokia Series 40 6212 feature phones. These three devices have been chosen because they have different form factors and input mechanisms: multi-touch screen and advanced gestures, stylus or a classical four-way scroller.
The proposed information architecture is depicted in Figure 1. The application will have an initial menu which will give access to the different functionalities provided by the portal: the latest news of "La Liga", the information about rounds, the information dedicated to specific teams and the global statistics. The latest news about "La Liga" or about an specific team will be presented as a master-detail list. We will also dedicate a specific presentation for club image galleries. At this abstraction level, we have divided the presentation of the information about rounds in two different views: one for the games and another for the standings. The statistics will be presented in a single view which will contain a nice bar diagram.
Now that we have a clear view of what we want to achieve and what is the information architecture of the application, the development activities can start. First of all, it is needed to to configure the development environment. For doing so, the following products must be installed:
Then, the MyMobileWeb SDK v4 and the MyMobileWeb Eclipse plugin compatible with such a version have to be installed and configured. Both of them can be downloaded from the MyMobileWeb's web site. The application can also be developed without the Eclipse plugin, but we strongly recommend to use it as it simplifies and accelerates the development process. The following step is to create a new MyMobileWeb project using the Eclipse Plugin. This new project is already set up and configured to start the development and testing cycles of the new application.
The first step that needs to be completed in the development process is the design of the flow of the application in accordance with the information architecture previously presented. An application flow in MyMobileWeb is divided into the so called Presentation Operations (OPs). An OP represents a use case and it is composed by the set of presentations and the flow between them that realizes such a use case. Thus, we can identify the following OPs for our portal:
InitialMenu: This is the first OP of the application and will be called once the application is invoked by the user. This OP will contain a presentation with a menu that will allow users to choose between the different functionalities offered by our portal.
News: It corresponds to the use case responsible for presenting a list of news and the detail of each news presented, so at least two presentations will be needed.
Rounds: This OP is in charge of presenting the games and standings for the latest rounds. As the standings and games are strongly related we have decided to include both in the same presentation but in different sections.
Clubs: This use case is concerned with the selection and presentation of information about a team. A presentation with a menu will allow users to select the team they want to know more about.
Gallery: The Gallery OP is intended to present an image gallery allowing the user to select and display. Although this OP could be merged with the "Clubs" OP we have separated them for modularization and reusing purposes, as in future versions of the portal might be needed in another context.
Statistics: The purpose of this OP is to display statistics automatically about clubs in graphic format.
Tickets: This OP is in charge of presenting a form where users can buy tickets for a match.
The next step is to specify our application flow using W3C's SCXML. Figure 2 graphically depicts the SCXML state machine corresponding to our application. In the following paragraphs we describe the SCXML formalisms and how they are mapped to the elements which intervene in an application flow: OPs, presentations, events resulting from user interaction and the application logic:
States: Each OP is modeled as a state that has as many substates as presentations such a OP is going to have. Following this rule, it can be seen that, for instance, the "News" OP is modeled as an state identified as "News" that has two substates: "newsList" and "newsDetail". Thus, there are two kinds of states: OP states and Presentation states. When the state machine is in a presentation state it means that the user is actually viewing and interacting with such a presentation. The framework guarantees that when a presentation state is reached the application will navigate to the corresponding page.
Transitions: The flow between OPs and presentations within an OP is modeled as transitions triggered by events raised by the interaction of the user with the application and (optionally) controlled by logical conditions that operate over the data model. For instance, you can see that the InitialMenu state (corresponding to the "InitialMenu" OP) has transitions to the other OPs it gives access. Such transitions are triggered when a menu option is selected and are conditioned by the value of the menu option actually selected.
Actions: Actions are executed when a new state is reached or when a transition is triggered. Actions can be used basically to express what application logic, Application Operations (OAs) in my MyMobileWeb terminology, should be executed. For example, when the state "newsDetail" is reached an Application Operation called "NewsOA" will be executed. Such OA will obtain from a RSS service a list with the latest news which will be displayed by the corresponding presentation. Actually, OAs are Java classes provided by the application programmer.
Apart from these transitions defined by the application programmer, MyMobileWeb adds automatically other transitions that deal with error conditions which may arise.
The Figure 3 depicts graphically the application flow using W3C's SCXML
<?xml version="1.0" encoding="UTF-8"?> <scxml xmlns="http://www.w3.org/2005/07/scxml" xmlns:mymw="http://morfeo-project.org/mymobileweb" version="1.0" initial="Soccer"> <state id="Soccer" mymw:category="Application"> <initial> <transition target="InitialMenu" /> </initial> <!-- General Transitions --> <transition event="lback.onclick" target="InitialMenu" /> <transition event="lindex.onclick" target="InitialMenu" /> <transition event="onrequest" cond="${mymw:matches('/app/club/(.+?)')}" target="Club"> <mymw:urlMappings> <mymw:bind var="sessionScope.club" /> </mymw:urlMappings> </transition> <!-- Use Cases --> </state> </scxml>
Figure 3. Application Flow using W3C's SCXML
Now we will decribe the flow for each use case:
InitialMenu: defining the flow for the first view. Go to section.
<state id="InitialMenu" mymw:category="UseCase" initial="InitialMenu.index"> <state id="InitialMenu.index" mymw:category="View"> <transition event="init.onclick" cond="${option == 'news'}" target="News"/> <transition event="init.onclick" cond="${option == 'club'}" target="Club.clubSelection"/> <transition event="init.onclick" cond="${option == 'last'}" target="Club.clubDetail"/> <transition event="init.onclick" cond="${option == 'rounds'}" target="Rounds"/> <transition event="init.onclick" cond="${option == 'statistics'}" target="Statistics"/> </state> </state>
Figure 4. Initial Menu Flow
Rounds: defining the flow for standings and games. Go to section.
<state id="Rounds" mymw:category="UseCase" initial="Rounds.round"> <state id="Rounds.round" mymw:category="View"> <onentry> <mymw:executeOA idOA="StandingsOA"/> <mymw:executeOA idOA="GamesOA"/> </onentry> <transition event="next.onclick" target="Rounds.round"/> <transition event="previous.onclick" target="Rounds.round"/> </state> </state>
Figure 5. Rounds Flow
News: defining the flow for news. Go to section.
<state id="News" mymw:category="UseCase" initial="News.newsList"> <state id="News.newsList" mymw:category="View"> <onentry> <if cond="${_MYMW_PREV_OP == 'InitialMenu'}"> <mymw:executeOA idOA="NewsListOA"/> <else/> <mymw:executeOA idOA="ClubNewsListOA"/> </if> </onentry> <transition event="read.onclick" target="News.newsDetail"/> <transition event="lback.onclick" cond="${_MYMW_PREV_OP == 'InitialMenu'}" target="InitialMenu"/> <transition event="lback.onclick" cond="${_MYMW_PREV_OP == 'Club'}" target="Club"/> </state> <state id="News.newsDetail" mymw:category="View"> <onentry> <if cond="${_MYMW_PREV_OP == 'InitialMenu'}"> <mymw:executeOA idOA="NewsDetailOA"/> <else/> <mymw:executeOA idOA="ClubNewsDetailOA"/> </if> </onentry> <transition event="lback.onclick" target="News.newsList"/> </state> </state>
Figure 6. News Flow
Gallery: defining the flow for photo gallery. Go to section.
<state id="Gallery" mymw:category="UseCase" initial="Gallery.gallery"> <state id="Gallery.gallery" mymw:category="View"> <onentry> <mymw:executeOA idOA="GalleryOA"/> </onentry> <transition event="myCarousel.onclick" target="Gallery.photo"/> <transition event="lback.onclick" target="Club"/> </state> <state id="Gallery.photo" mymw:category="View"> <transition event="lback.onclick" target="Gallery.gallery"/> </state> </state>
Figure 7. Gallery Flow
Statistics: defining the flow for statistics about clubs. Go to section.
<state id="Statistics" mymw:category="UseCase" initial="Statistics.barchar"> <state id="Statistics.barchar" mymw:category="View"> <transition event="chart.onclick" target="Club"> <mymw:executeOA idOA="BarCharOA"/> </transition> </state> </state>
Figure 8. Statistics Flow
Tickets: defining the flow for a form of buying. Go to section.
<state id="Tickets" mymw:category="UseCase" initial="Tickets.form"> <state id="Tickets.form" mymw:category="View"> <transition event="send.onsubmit" target="Tickets.complete" /> <transition event="lback.onclick" target="Club" /> </state> <state id="Tickets.complete" mymw:category="View"> <transition event="ok.onsubmit" target="Club" /> <transition event="lmap.onclick" target="Tickets.map" /> <transition event="lback.onclick" target="Tickets.form" /> </state> <state id="Tickets.map" mymw:category="View"> <onentry> <mymw:executeOA idOA="MapOA" /> </onentry> <transition event="lback.onclick" target="Tickets.complete" /> </state> </state>
Figure 9. Tickets Flow
This section talks about the development of an application guided by MyMobileWeb's UI components.
The presentation layer in MyMobileWeb is developed using the IDEAL2 language. We will start looking into IDEAL2 using the
presentation which will give access to the different functionalities provided by our portal (index). The XML corresponding
to such presentation can be seen in Figure 10. There are two main blocks: the resources block in which dependencies are declared (script code, CSS sheets, etc.) and the
ui section devoted to the structure of the user interface. IDEAL2 only is concerned with the specification of the presentation
structure. The look-and-feel and layout is controlled by means of CSS. This approach has the advantage that the user interface
can be customized for different devices without duplicating the XML code.
A presentation in IDEAL2 is structured in sections. There are two (optional) special sections, the header and the footer. If declared, these two sections will always appear at the top or the bottom of the final page regardless of pagination.
As in our portal the header and the footer are always the same, they include common content to avoid duplication. A section typically contains one or more div blocks which act as second level containers. Different user interface elements can appear inside a div. In our first example, we can see a menu which contains as many options as functionalities are provided by our portal. It
is important to observe that the identifier assigned to the menu options it is the same as the identifier used by the SCXML
state machine.
<?xml version="1.0" encoding="utf-8"?> <!DOCTYPE ideal2> <ideal id="index" title="La liga"> <resources> <link id="icon" rel="shortcut icon" expr="!mymw:belongsTo('iPhone')" type="image/x-icon" href="${myFavIcon}" /> <link id="iconIPhone" rel="apple-touch-icon" expr="mymw:belongsTo('iPhone')" href="${myFavIcon}" /> <link rel="stylesheet" id="soccerStyle" href="soccer.css" /> </resources> <ui> <body> <header id="header"> <include content="Common/generic/common/header" /> </header> <section id="main"> <div> <menu id="init" ref="option" class="soccer"> <a id="news" class="decorate" longtitle="Soccer News" resourceid="news">News</a> <a id="club" class="decorate" longtitle="My club" resourceid="team">My club</a> <a id="rounds" class="decorate" longtitle="Standings and games" resourceid="table">Rounds</a> <a id="statistics" class="decorate" longtitle="Winners statistics" resourceid="statistics">Statistics</a> </menu> </div> </section> <footer id="footer"> <separator class="line" /> <include content="Common/generic/common/powered" /> </footer> </body> </ui> </ideal>
Figure 10. Presentation: Initial Menu
To specify the look-and-feel and layout of presentations, IDEAL2 is used in conjunction with CSS. CSS sheets and styles
are bound to presentations using the same syntax as in HTML. Apart from the standard CSS 2 properties, MyMobileWeb defines
extended properties. Figure 11 shows the style we have assigned to our menu. It will be displayed as a vertical menu i.e. one option per line, and will
have alternative background colors. It is noteworthy that MyMobileWeb provides default CSS styles (optimized for different
device families) for all the user interface elements which has been proved to be extremely helpful for developers. Other elements
of our page are also affected by this style sheet. For example, hyperlinks (a elements) are going to be displayed with their accompanying images. This example also demonstrates another important functionality
of MyMobileWeb, which is how abstract user interface elements can be rendered in different ways using the display-as style. In this particular case the separator element is going to be realized as a horizontal rule. Other options are a line break or an image. This abstract UI rendering
decision can also be made automatically by the adaptation engine (taking into account the characteristics of the device and
web browser).
menu.soccer {
layout:vertical;
align:left;
colored:true;
background-color1:#ffd8ad;
background-color2:#f7f6ef;
white-space:wrap;
width:100%;
}
a.decorate {
img-display:both;
}
separator.line {
display-as:hr;
}Figure 11. CSS Styles for inital menu
We would like to decorate our menu with nice images. Images in a mobile environment can be problematic for two reasons: not all devices or web browsers support
all image formats and the optimal image size can vary depending on the screen size available. To deal with these issues, MyMobileWeb
provides two different mechanisms: selection and transcoding. Selection is a functionality that consists of choosing the best
image from a set of alternatives (media set). Transcoding is the transformation of a source image provided by the developer
in a target image which satisfies all the restrictions in terms of formats and optimal size. The usage of transcoding or selection
depends on the availability of different sizes and formats or in the nature of the images themselves, as the transformation
process may be degrading. Nonetheless, selection and transcoding are not exclusive, i.e. images can be first selected and
then transcoded. In our example, it is specified an identifier (resourceid) of the media set that has to be used. The images that are part of each media set have to be left in a configurable directory
in the application space.
Figure 12 shows how our presentation is displayed in different devices and browsers. You can see how MyMobileWeb adapts the interface and look-and-feel to be the most suitable for each device. For example, the iPhone menu is displayed in big fonts to allow a best touch selection.
The previous example showed a presentation which structure is totally defined at design time. Now we are going to demonstrate
(Figure 13) how to create a dynamic presentation which will depend on data or content calculated at runtime. In this case we also have
a menu for club selection. As the number of clubs in the national league can vary depending on the season, we would like to
obtain the name of the clubs from a remote service. Thus, we specify a menu as well, but instead of putting directly the options
in the presentation we insert a template option with a repetition structure (repeat-nodeset attribute). This repetition structure will be controlled by a collection provided by the application logic described below.
In this example, it is also shown how the attribute values can be made dynamic (using the JSP 2.0 ${x} syntax).
<?xml version="1.0" encoding="utf-8"?> <!DOCTYPE ideal2> <ideal id="index" title="My Club"> <resources> <link id="icon" rel="shortcut icon" expr="!mymw:belongsTo('iPhone')" type="image/x-icon" href="${myFavIcon}" /> <link id="iconIPhone" rel="apple-touch-icon" expr="mymw:belongsTo('iPhone')" href="${myFavIcon}" /> <link rel="stylesheet" id="soccerStyle" href="soccer.css" /> </resources> <ui> <body> <header id="header"> <include content="Common/generic/common/header" /> </header> <section id="main"> <div id="p1" class="common title.common" title="My Club"> <menu id="myMenu" ref="club" class="clubs center"> <a id="header" repeat-nodeset="clubList" src="${clubList.current.image}" href="${clubList.current.href}"> ${clubList.current.name} </a> </menu> </div> </section> <footer id="footer"> <include content="Common/generic/common/footer" /> <separator class="line" /> <include content="Common/generic/common/powered" /> </footer> </body> </ui> </ideal>
Figure 13. Presentation: Dynamic Menu
Application logic in MyMobileWeb is specified by means of the so called Application Operations (OAs). An OA is a Java class
that implements a well-known interface which defines an operation to be provided by developers: execute. Such operation has an input parameter which represents the current application data model (Context class). The Context class acts as an object container. Each contained object is associated with an identifying key. In the example below, first
we obtain the list of clubs by calling a remote service, being each club a Java Bean structure with an attribute per field
we need at the presentational level. The whole club list is represented by a Java List container. Once we have the container filled, we store it in the data model (setElement method) under the key 'clubList'. It can be observed that this key is exactly the same as the specified in the repeat-nodeset attribute in the IDEAL2 authoring unit. Also the names of the Java Bean attributes have to be equal to the names used in
the presentation (image, href and name).
public class ClubsOA extends BasicApplicationOperation {
public void execute(Context the_context) throws OAException {
List<Club> clubs = DataHolder.getInstance().getClubsInfo();
List<Map<String, String>> data = new ArrayList<Map<String, String>>();
for (Club club : clubs) {
Map<String, String> aux = new HashMap<String , String> ();
aux.put("name", club.getName());
aux.put("href", club.getHref());
aux.put("image", club.getImage());
data.add(aux);
}
the_context.setElement("clubList", data);
}
}Figure 14. Application Operation: club list
One of the most important functionalities provided by MyMobileWeb is the awareness about the device and web browser used, i.e. the delivery context, thanks to the information provided by the Device Description Repository Service. This functionality can be exploited by authors to customize their application for a broad range of devices. In the example above, you can see how we provide a specific icon for the iPhone. Related to this is the style overriding feature intended to override properties of a style for specific delivery contexts. Using such a feature we can for instance, change the layout and appearance of our menu: vertical for iPhone devices, grid for the rest. Developers can specify by configuration their own device families or reuse those provided by the platform.
menu.clubs {
img-display: only;
layout: grid;
cols: 4;
border-width: 0;
background-color1: #ffd8ad;
background-color2: #f7f6ef;
}Figure 15. CSS Styles for all devices
menu.clubs {
img-display:both;
align :left;
colored: true;
background-color1:#ffd8ad;
background-color2:#f7f6ef;
}Figure 16. Specific CSS Styles for iPhone
We are going to show how to use tables in the MyMobileWeb framework by focusing on the "Rounds" functionality. The idea is
to provide information about each round by displaying the games and the standings. To demonstrate these features, we have
designed the presentation below. Such presentation has two sections: one for the games and other for the standings. Each section
has a dynamic table controlled by a data model collection specified by means of the repeat-nodeset attribute. As previously noted such an attribute indicates that there will be as many table rows as indicated by a collection
that has to be present in the application data model. Our tables are dynamic because they will display different information
depending on the round considered. Both tables belong to the 'paginate' class. This means that if the number of rows exceeds
the maximum number of rows that device can manage reasonably, they should be automatically paginated by MyMobileWeb. Some
of the columns of the standings table are subject to a condition over the Delivery Context to avoid having too many columns
in small devices. The corresponding OAs that obtain the games and standings from a remote service are not shown due to space
limitations, but they follow the same structure as the one previously described.
<?xml version="1.0" encoding="utf-8"?> <!DOCTYPE ideal2> <ideal id="index" title="Rounds"> <resources> <link id="icon" rel="shortcut icon" expr="!mymw:belongsTo('iPhone')" type="image/x-icon" href="${myFavIcon}" /> <link id="iconIPhone" rel="apple-touch-icon" expr="mymw:belongsTo('iPhone')" href="${myFavIcon}" /> <link rel="stylesheet" id="soccerStyle" href="soccer.css" /> </resources> <ui> <body> <header id="header"> <include content="Common/generic/common/header" /> </header> <section id="main" class="tabs"> <section id="games" title="Games" resourceid="team"> <div> <table id="gamesTable" class="soccer paginate"> <th class="header"> <td>Date</td> <td>Games</td> </th> <tr repeat-nodeset="games"> <td><output ref="date" /></td> <td><output ref="game" /></td> </tr> </table> </div> </section> <section id="standings" title="Standings" resourceid="table"> <div> <table id="standingsTable" class="soccer paginate"> <th class="header"> <td>Pos</td> <td>Name</td> <td>W</td> <td expr="mymw:deviceWidth() gt 300">L</td> <td expr="mymw:deviceWidth() gt 300">T</td> <td>Pts</td> </th> <tr repeat-nodeset="standings"> <td><output ref="pos" /></td> <td class="bold"><output ref="name" /></td> <td><output ref="won" /></td> <td><output ref="lost" /></td> <td><output ref="tied" /></td> <td class="bold"><output ref="pts" /></td> </tr> </table> </div> </section> </section> <footer id="footer"> <include content="Common/generic/common/footer" /> <separator class="line" /> <include content="Common/generic/common/powered" /> </footer> </body> </ui> </ideal>
Figure 18. Presentation: Sections and Tabs
section.tabs {
display-as: tabs;
tab-not-selected-color: #f7f6ef;
tab-selected-color: #ffd8ad;
tab-link-selected-color: white;
tab-link-not-selected-color: black;
}Figure 19. CSS Styles for tabs
Defining styles for the previous tables: the background colors of the rows alternate and they will be paginated.
table.paginate {
paginate:true;
}
table.soccer {
page-position:bottom;
colored:true;
background-color1:#ffd8ad;
background-color2:#f7f6ef;
width:100%;
border-color:#900000;
page-control-type:image;
}
tr.header {
color:white;
background-color:#ec894b;
font-weight:bold;
}Figure 20. CSS Styles for pagination and colors
public class StandingsOA extends BasicApplicationOperation {
public void execute(Context the_context) throws OAException {
List<Map<String, Object>> table = new ArrayList<Map<String, Object>>();
DataHolder dataHolder = DataHolder.getInstance();
Collection<Club> list = dataHolder.getClubsInfo().values();
int pos = 1;
for (Iterator<Club> iterator = list.iterator(); iterator.hasNext();) {
Club club = iterator.next();
Map<String, Object> auxi = new HashMap<String, Object>();
auxi.put("pos", pos++);
auxi.put("name", club.getName());
auxi.put("won", club.getWon());
auxi.put("lost", club.getLost());
auxi.put("tied", club.getTied());
auxi.put("pts", club.getPoints());
auxi.put("id", club.getId());
table.add(auxi);
}
the_context.setElement("standings", table);
}
}Figure 21. Application Operation: loading standings
Here we are going to get the games by invoking a service provided by Spanish Profesional Football League
public class GamesOA extends BasicApplicationOperation implements ResultsOAVocabulary {
private final String RESULTS_URL = "http://www.lfp.es/DesktopModules/IWeb/webservice.asmx/ProximaJornada";
public void execute(Context the_context) throws OAException {
Document doc = callService();
List<Map<String, String>> data = getModel (doc);
the_context.setElement("games", data );
}
// More methods...Figure 22. Application Operation: loading games
The Figure 23 above shows the final result obtained. It can be observed that the two sections are presented in two different tabs. The
tab layout is one of the predefined layouts that MyMobileWeb provides. This functionality can be easily achieved by means of a CSS style.
The next example shows how a list of news can be presented to the user. Each news item will contain a title, text content,
an accompanying image and optionally other metadata such as author, ratings, etc. To display properly this item set, we have
decided to use a placard component. A placard element enables the combination of text, images and other elements in different positions. As usual,
for those less capable devices MyMobileWeb will gracefully degrade the placard. MyMobileWeb has different placard layouts
that correspond to the most common use cases. The role attribute is used to convey the purpose of each element within the placard, conditioning the place in which it will be finally rendered. Our placard is affected by a repeat-nodeset attribute, as the news are dynamically obtained from an RSS service. In addition this example demonstrates how the range component can be used to display ratings, which are very common these days in web portals.
Here we are going to show the image, the subject, author (if available) and date associated to the news item but depending
on the delivery context more or less information will be displayed. For example, when the device width is less or equal than
300 the image will not be displayed so we can improve the user experience according to target device (see expr="dcn:deviceWidth() gt 300"). On the other hand we decide to show the rating news so we use the range control for expressing it by means of stars.
Attention: if you need to include a hyperlink inside repeat-nodeset, you should define the value attribute for this a tag. Then you can know the hyperlink was clicked getting the request parameter called VAL.
String value = ContextUtil.getEventParam(the_context, EventsParams.PARAMETER_VALUE);
Figure 26. Getting event parameter
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE ideal2> <ideal id="newsList" title="La liga News"> <resources> <link id="icon" rel="shortcut icon" expr="!mymw:belongsTo('iPhone')" type="image/x-icon" href="${myFavIcon}" /> <link id="iconIPhone" rel="apple-touch-icon" expr="mymw:belongsTo('iPhone')" href="${myFavIcon}" /> <link rel="stylesheet" id="soccerStyle" href="soccer.css" /> </resources> <ui> <body> <header id="header"> <include content="Common/generic/common/header" /> </header> <section id="main"> <div id="p1" class="center common title.common" title="Information" expr="totalItems eq 0 "> <image alt="info" id="info" resourceid="info" /> <p class="bold"><span>Not available RSS Feeds</span></p> </div> <div class="news common title.common" title="${newsTitle}" id="para1" expr="totalItems gt 0"> <placard id="placard" class="${newsCard}" repeat-nodeset="news"> <p role="mymw:subtext" class="news bold"> <span>${subject}</span> <a id="read" value="${value}"> read more...</a> </p> <p expr="dcn:deviceHeight() gt 300" role="mymw:subtext" class="news"> <span class="sub">Date: </span> <span class="sub italic">${date}</span> <span expr="!empty(author)" class="sub"> and author: </span> <span expr="!empty(author)" class="sub italic">${author}</span> </p> <p expr="dcn:deviceHeight() gt 300" role="mymw:subtext" class="news"> <range id="rating" expr="dcn:deviceHeight() gt 300" class="rating" start="1" end="5" step="1" ref="rating" /> </p> <image expr="dcn:deviceWidth() gt 300" role="mymw:icon-left" class="news" alt="img" id="img" src="${image}" /> </placard> </div> </section> <footer id="footer"> <include content="Common/generic/common/footer" /> <separator class="line" /> <include content="Common/generic/common/powered" /> </footer> </body> </ui> </ideal>
Figure 27. Presentation: News List
This application operation is charge of getting latest news.
public class NewsListOA extends BasicApplicationOperation {
public void execute(Context the_context) throws OAException {
RSSDocument doc = RSSParserFactory.getInstance().getPlugin().parse(DataHolder.getInstance().getNews());
if (doc != null) {
loadRSS(the_context, doc);
} else {
the_context.setElement("totalItems", 0);
}
}
private void loadRSS(Context the_context, RSSDocument doc) {
List<Map<String, String>> news = new ArrayList<Map<String, String>>();
SimpleDateFormat format = new SimpleDateFormat("EEE, MMM d, yyyy");
List<RSSItem> list = doc.getItems();
int cont = 1;
for (Iterator<RSSItem> iterator = list.iterator(); iterator.hasNext();) {
RSSItem item = iterator.next();
Map<String, String> map = new HashMap<String, String>();
map.put("subject", item.getFilteredTitle());
String imageURL = item.getImage();
if (imageURL == null)
imageURL = "resource/images/unavailable/generic/un.gif";
map.put("image", imageURL);
map.put("author", item.getAuthor());
map.put("date", format.format(item.getDate()));
map.put("value", Integer.toString(cont - 1));
if (cont % 2 == 0) {
map.put("rating", "3");
map.put("card", "card even");
} else {
map.put("rating", "4");
map.put("card", "card odd");
}
news.add(map);
cont++;
if (cont > MAX_NUM_NEWS)
break;
}
the_context.setElement("totalItems", news.size());
the_context.setElement("news", news);
}
Figure 28. Application Operation: getting latest news
With regards to the CSS styles, it is worth to having a look at the style properties assigned to the image within the placard. The transcode property indicates that the image associated to each news item will be automatically transformed to fit in the area reserved
to it. It is noteworthy that in this particular case there is no better option than transcodification because such an image
comes in an arbitrary size from an Internet RSS feed. Lastly, to avoid image deformation, we have indicated that the aspect
ratio should be conserved.
placard.newsCard {
layout: card;
width: 100%;
border-radius: 6px;
margin: 1;
}
placard.newsOddCard {
background-color:#ffd8ad;
}
placard.newsEvenCard {
background-color:#ec894b;
}
div.news {
background-color: white;
}
image.news {
transcode:true;
weight-width:25;
aspect-ratio:true;
vertical-align: top;
}Figure 29. CSS Styles for placard and transcoding
Figure 30 shows how the placard has been finally rendered on different devices. When the “read more” hyperlink is activated the entire news item will be
showed. Such functionality has been implemented using a simple IDEAL2 authoring unit with a (transcoded) image and a paragraph
with dynamic contents.
MyMobileWeb provides an abstract component called carousel intended to display sequentially a catalogue of objects to be selected by the user. This feature can be used in our portal
to show club’s image galleries. Figure 31 is an IDEAL2 excerpt declaring a carousel of images about clubs. As our images are provided by an external service as (Flickr) we will use the repeat-nodeset attribute.
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE ideal2> <ideal id="index" title="by Flickr"> <resources> <link id="icon" rel="shortcut icon" expr="!mymw:belongsTo('iPhone')" type="image/x-icon" href="${myFavIcon}" /> <link id="iconIPhone" rel="apple-touch-icon" expr="mymw:belongsTo('iPhone')" href="${myFavIcon}" /> <link rel="stylesheet" id="soccerStyle" href="soccer.css" /> </resources> <ui> <body> <header id="header"> <include content="Common/generic/common/header" /> </header> <section id="main"> <div class="center common title.common" id="container" title="by Flickr"> <carousel id="myCarousel" ref="myImage"> <image id="header" repeat-nodeset="gallery" src="${gallery.current.src}" class="thumbnail" alt="${gallery.current.title}" value="${gallery.current.value}" /> </carousel> </div> </section> <footer id="footer"> <include content="Common/generic/common/footer" /> <separator class="line" /> <include content="Common/generic/common/powered" /> </footer> </body> </ui> </ideal>
Figure 31. Presentation: Gallery of images
Now we are going to get images by invoking Flickr service which returns a list of photos matching some criteria (futbol plus club name).
public class GalleryOA extends BasicApplicationOperation {
public void execute(Context the_context) throws OAException {
String club = (String) the_context.getElement("club");
Club club = DataHolder.getInstance().getClubInfo(club);
Flickr f = new Flickr("78as6d76as87d6a89786asdf5c671d9");
SearchParameters keyword_search = new SearchParameters();
String[] search_parameters = { club.getName(), "futbol" };
keyword_search.setTags(search_parameters);
keyword_search.setTagMode("all");
List<Map<String, String>> aux = new ArrayList<Map<String, String>>();
try {
PhotoList photolist = f.getPhotosInterface().search(keyword_search,30, 1);
int cont = 0;
for (Iterator<Photo> iterator = photolist.iterator(); iterator.hasNext();) {
Photo photo = iterator.next();
Map<String, String> map = new HashMap<String, String>();
map.put("src", photo.getThumbnailUrl());
map.put("title", photo.getTitle());
map.put("value", photo.getMediumUrl());
aux.add(map);
}
} catch (Exception e) {
log.error(e);
}
the_context.setElement("gallery", aux);
}
}Figure 32. Application Operation: loading images
Now we are going to apply a center alignment for the carousel component and clear an area around the images applying the padding property.
image.thumbnail{
padding:1;
vertical-align: middle;
transcode:true;
width:75;
aspect-ratio:true;
}Figure 33. CSS Styles for images
MyMobileWeb includes an extension library which provides the capability to render statistical graphics for multiple devices
in different formats: vector (SVG) or raster images. The library supports different kind of graphics: pie, bar, scatter, etc. The example below demonstrates how easily we can support the statistics functionality required for our portal. A component
called barchart must be included. Then, we use the src attribute to convey the data source (XML file) to be used. In this particular case we want to show a bar chart which depicts
the number of championships (national and European) won by the different clubs throughout history. We need also to specify
the captions in each axis and the corresponding legends.
<chart id="data" type="BarChart"> <data> <serie name="Leagues"> <item y="31"/> <item y="19"/> <item y="9"/> <item y="6"/> <item y="2"/> <item y="1"/> </serie> <serie name="Champions"> <item y="9"/> <item y="3"/> <item y="0"/> <item y="0"/> <item y="0"/> <item y="0"/> </serie> </data> <axes> <axisx name="Club"> <value>Real Madrid</value> <value>Barcelona</value> <value>Atletico</value> <value>Valencia</value> <value>Deportivo</value> <value>Sevilla</value> </axisx> </axes> </chart>
Figure 35. XML data source: series and axis
The platform tries to adjust the graphic to the display but what happens when the device changes the orientation? We include a Javascript code for updating the graphic when the orientation changes. We can add an event listener to orientation change events so when it happens we will invoke the Rendering Engine module to create a new statistical graphic with new measures via AJAX.
reload = function () {
var params = {};
params["fid"] = 'barchart';
params["aj"] = 1;
var callbacks = {
onsuccess: function(xhr) {
mymw.ui.setFragment("container", xhr.responseText);
},
onerror: function(xhr) {
mymw.ui.setFragment(id, "Unable to get contents");
}
};
mymw.ajax.submit("POST", _MYMW_CTX_NAME + "DH?", params, callbacks);
}
mymw.orientation.addObserver( function() { reload(); } );Figure 36. Updating the graphic
This Javascript code is only included when the target device supports orientation changes and its display is not square
(see expr="mymw:propertyValue ('supportedOrientations')['90'] and dcn:deviceWidth() != dcn:deviceHeight()"). In addition we need to include the orientation and user interface modules.
<?xml version="1.0" encoding="utf-8"?> <!DOCTYPE ideal2PlusCharts> <ideal id="barchar" title="Statistics"> <resources> <link id="icon" rel="shortcut icon" expr="!mymw:belongsTo('iPhone')" type="image/x-icon" href="${myFavIcon}" /> <link id="iconIPhone" rel="apple-touch-icon" expr="mymw:belongsTo('iPhone')" href="${myFavIcon}" /> <link rel="stylesheet" id="soccerStyle" href="soccer.css" /> <script type="text/javascript" module="http://morfeo-project.org/mymobileweb/modules#Orientation" /> <script type="text/javascript" src="script/ISO-8859-1/All/mymw-ui_min.js" /> <script expr="mymw:propertyValue ('supportedOrientations')['90'] and dcn:deviceWidth() != dcn:deviceHeight()" type="text/javascript" src="myScript/update.js" /> </resources> <ui> <body> <header id="headerSection"> <include content="Foot/generic/foot/header" /> </header> <section id="mainSection"> <div id="container" class="center nowrap"> <barchart id="chart" alt="Leagues" src="resource/charts/teams/barchart.xml" ref="selectedBar" class="myChart"> <label>List of winners</label> <caption axis="x">Club</caption> <caption axis="y">Number</caption> </barchart> </div> </section> <footer id="footerSection"> <include content="Foot/generic/foot/foot" /> <separator class="line" /> <include content="Foot/generic/foot/powered" /> </footer> </body> </ui> </ideal>
Figure 37. Presentation: Statistics
We can indicate the position where the legend will be displayed by means of the legend-position property.
In this presentation we design a form to introduce a name and e-mail address and finally a telephone, number of tickets and
date's match can be included optionally. We need to validate the data filled by the user. How could I do this? The platform
executes automatic validation that can be local (resolved in scripting language) or remote (using the validation information
generated previously). How should I indicate the kind of validations? It's very easy, the validations are defined by means
of W-CSS styles (E.g. required:true). The validations can be: required, format, type and range validations. In this case, we have decided to use required and
format. The full name and e-mail address are required but the telephone number must satisfy a numeric format. There are error
messages for automatic validations but you can modify them if you want. The messages support variable substitution involving
local parameters and context variables specified by expression languages.
Now we are going to simplify the task of filling forms by means of the recommendations. What does it mean? It's a servlet that receives the term and returns a JSON object composed of matchings. In runtime, a
Javascript library loads this object and shows the recommendations automatically. In this example, the servlet has a list
of teams.
<?xml version="1.0" encoding="utf-8"?> <!DOCTYPE ideal2> <ideal id="index" title="Tickets"> <behaviour> <listener event="click" target="dateField" function="onselect_dateField(y,m,d)" /> </behaviour> <resources> <link rel="stylesheet" id="soccerStyle" href="soccer.css" /> <script module="http://morfeo-project.org/mymobileweb/modules#Orientation" /> <script module="http://morfeo-project.org/mymobileweb/modules#Autocompletion" /> <script module="http://morfeo-project.org/mymobileweb/modules#Recommendation" /> <script type="text/javascript" src="myScript/calendar.js" /> </resources> <ui> <body> <header id="headerSection"> <include content="Foot/generic/foot/header" /> </header> <section id="mainSection"> <div id="p1" class="register common title.common" title="Buy Tickets"> <input id="name" about-class="foaf:Person" ref="name" about-prop="foaf:name" class="req register"> <label class="bold">Full name:</label> </input> <input id="email" about-class="foaf:Person" ref="email" about-prop="foaf:mbox" class="req register"> <label class="bold">Email:</label> </input> <input id="telephone" about-class="foaf:Person" ref="telephone" about-prop="foaf:telephone" validationtype="Integer" class="telephone register"> <label>Telephone:</label> </input> <range id="count" start="1" end="5" step="1" ref="count" class="req"> <label class="bold">Tickets:</label> </range> <input id="team" ref="team" class="req register" recommendations="true" recommendationsURI="/Soccer/Team"> <label class="bold">Against:</label> </input> </div> <div id="p1_date" class="calendar common"> <inputDate ref="date" class="req clientcalendar" id="dateField"> <label id="date">Date:</label> </inputDate> </div> <div id="p2" class="send center common"> <submit id="send" value="Buy" /> </div> </section> <footer id="footerSection"> <include content="Foot/generic/foot/foot" /> <separator class="line" /> <include content="Foot/generic/foot/powered" /> </footer> </body> </ui> </ideal>
Figure 40. Presentation: Forms
For this presentation we have decided to use a grid layout with two columns (see div.register). If you want to indicate that an input is required you need to set the required property to true. The platform shows a mark close the input's label. Finally, we have designed a numeric format for the telephone: zero or
more numeric characters (input-format:"\*N")
div.register {
layout:grid;
cols:2;
white-space: nowrap;
}
input.req {
required: true;
}
input.register {
size: 15;
}
input.telephone {
input-format:"\*N";
}Figure 41. CSS Styles for forms
MyMobileWeb includes an UI component called map which lets authors embed a map viewer in IDEAL2 pages. This component is especially designed for using AJAX although for
delivery contexts that don't support it the platform renders it like static maps with a set of controls. The map viewer can
get maps from different providers like Google Maps, Open Street Map and WMS services in general. A developer can benefit from a set of functionalities: clustering of place marks, routes, photo
overlays, etc...
In following sections we are going to explain different examples working with maps.
In this section we are going to display a map with a set of place marks. Setting the provider attribute we can choose our favourite map provider, e.g: Google Maps or Open Street Map. In this example, the developer only indicates the center of the map by means of the role maps:mapcenter and a set of place marks (labeled coordinates in WGS-84 format). If a developer provides a number of place marks very high the platform will apply a clustering algorithm grouping
close points (imagine hundreds of marks in the same view in a mobile environment).
<?xml version="1.0" encoding="utf-8"?> <!DOCTYPE ideal2> <ideal id="in" title="Map"> <resources> <link rel="stylesheet" id="zatStyle" href="soccer.css" /> </resources> <ui> <body> <section id="main"> <div id="container" class="center"> <map id="myMap" zoomLevel="15" ref="myMark" controls="true" class="example" provider="Google"> <placemark id="mapCenter" role="maps:mapcenter"> <point> <coordinates>${mapCenter.latitude},${mapCenter.longitude}</coordinates> </point> </placemark> <placemark id="myPoints" repeat-nodeset="placemarks" value="${placemarks.current.value}"> <label>${label}</label> <point> <coordinates>${latitude},${longitude}</coordinates> </point> </placemark> </map> </div> </section> <footer id="footerSection"> <include content="Foot/generic/foot/foot" /> </footer> </body> </ui> </ideal>
Figure 43. Presentation: Place marks
Now we are going to get place marks by invoking Zaragoza END POINT service which returns a list of POI's.
public void execute(Context the_context) throws OAException {
List<Map<String, String>> placemarks = SPARQLEngine.getInstance().getPlaceMarks();
int cont = 0;
for (Map<String, String> placemark: placemarks) {
placemark.put("value", Integer.toString(cont++));
}
the_context.setElement("placemarks", placemarks );
Point center = new Point();
center.setLatitude (Constants.CENTER_LAT);
center.setLongitude (Constants.CENTER_LNG);
the_context.setElement("center", center );
}Figure 44. Application Operation: loading place marks
We can indicate a set of layers that will be displayed by means of CSS styles (layers depend on the provider).
In this presentation we are going to show a clickable photo over a map. In this case, we have to define a photooverlay tag with two children: the icon and the photo (using the role attribute). Defining the ref attribute we can know the photo that was clicked because of an event was thrown from the client (we could define a flow based
on this interaction, for example to show information about the photo). In this example we use Open Street Map as our provider of maps.
<map id="myMap" zoomLevel="14" ref="myOption" provider="OpenStreetMap"> <placemark id="mapCenter" role="maps:mapcenter"> <point> <coordinates>${mapCenter.latitude},${mapCenter.longitude}</coordinates> </point> </placemark> <photooverlay id="photo"> <label>${photo.title}</label> <image id="ph" role="maps:photo" alt="photo" src="${photo.src}" class="thumbnail"/> <image id="icon" role="maps:icon" alt="icon" src="${photo.src}" class="icon"/> <point> <coordinates>${photo.latitude},${photo.longitude}</coordinates> </point> </photooverlay> </map>
Figure 47. Presentation: Photo Overlay
We will use the transcoding module to generate the icon and the photo with the suitable width and height for each delivery context.
image.thumbnail {
transcode: true;
width: 75;
aspect-ratio: true;
}
image.icon {
transcode: true;
height: 40;
width: 40;
aspect-ratio: false;
}Figure 48. CSS Styles for images
Here we are going to show the route between two points using the kindness of MyMobileWeb. A developer may specify the origin and destination either as civil address or as WGS-84 coordinates, in addition a developer can define a set of waypoints or stopovers which define the route, the difference between both is that the waypoints are not displayed.
Automatically the platform provides different views: the route over the map, textual description and the street view of
the current point. In addition, users can toggle among different travel modes by means of a set of buttons displayed over
the map (driving, walking,..).
<map id="myMap" zoomLevel="15" provider="Google"> <placemark id="mapCenter" role="maps:mapcenter"> <point> <coordinates>${mapCenter.latitude},${mapCenter.longitude}</coordinates> </point> </placemark> <route> <placemark id="stop" repeat-nodeset="route" role="${route.current.role}"> <label>${label}</label> <point> <coordinates>${latitude},${longitude}</coordinates> </point> </placemark> </route> </map>
Figure 50. Presentation: Routes
Calculating the origin and destination of the route.
public void execute(Context the_context) throws OAException {
Point center = new Point();
center.setLatitude (Constants.CENTER_LAT);
center.setLongitude (Constants.CENTER_LNG);
the_context.setElement("center", center );
List<Map<String, String>> route = new ArrayList<Map<String, String>>();
Map<String, String> place = new HashMap<String, String>();
place.put("role", "maps:origin");
place.put("label", origin.getAddress());
place.put("latitude", origin.getLatitude());
place.put("longitude", origin.getLongitude());
route.add(place);
place = new HashMap<String, String>();
place.put("role", "maps:destination");
place.put("label", destination.getAddress());
place.put("latitude", destination.getLatitude());
place.put("longitude", destination.getLongitude());
route.add(place);
the_context.setElement("route", route);
}Figure 51. Application Operation: setting origin and destination
A typical use case is to introduce locations in applications in which users can lose a lot of time. MyMobileWeb incorporates an UI component that provides a map in which users can locate an address easily. In addition, the platform will set the coordinates (in WGS-84 format) on context and developers can get it (imagine users introducing latitude and longitude in the page).
<?xml version="1.0" encoding="utf-8"?> <!DOCTYPE ideal2> <ideal id="index" title="Paso 1"> <resources> <link rel="stylesheet" id="myStyle" href="pleasefix.css" /> </resources> <ui> <body> <section id="main"> <div class="native common title.common" title="Localización"> <inputLocation id="inpLoc" ref="address" class="pleasefix" provider="Google"> <label>Address:</label> </inputLocation> </div> <div class="common"> <submit id="next" value="Siguiente" /> </div> </section> <footer id="footer"> <include content="Foot/generic/foot/foot" /> <separator class="line" /> <include content="Foot/generic/foot/powered" /> </footer> </body> </ui> </ideal>
Figure 53. Presentation: InputLocation
In this example we need to know the coordinates associated with the address that an user have introduced. This information
is available in context automatically, MyMobileWeb initializes a java.util.Map that contains the address, latitude and longitude whose key in context is defined in the attribute ref by the authors. How it works? MyMobileWeb gets the coordinates from the provider API in rich delivery contexts or by invoking
a Google Geocoding Service for the rest.
public void execute(Context the_context) throws OAException {
Map ref = (Map) the_context.getElement ("address");
String latitude = ref.get (InputLocationVocabulary.LATITUDE);
String longitude = ref.get (InputLocationVocabulary.LONGITUDE);
String addr = ref.get (InputLocationVocabulary.ADDRESS);
}Figure 54. Application Operation: getting locations
In this section we are going to introduce the media element which allows to render different media resources (video, audio, …) in accordance with the restrictions imposed by the delivery context.
Following subsections show two examples: using static sources and dynamic sources obtained from Youtube.
In this case we are going to use a media element which is composed of two representations, one of them is a Flash Video and the other is a streaming video in 3gpp format. The platform automatically knows that formats are supported by the set of media players installed in the target device. In this way, a developer only needs to provide a set of representations of the same element and it is responsibility of MyMobileWeb instantiates the specific media player for each media type.
<?xml version="1.0" encoding="utf-8"?> <!DOCTYPE ideal2> <ideal id="in" title="MyMW-Video"> <resources> <link rel="stylesheet" id="zatStyle" href="soccer.css" /> </resources> <ui> <body> <section id="main"> <div id="container" class="center"> <media id="myVideo" poster="http://i.ytimg.com/vi/7QWThlpRpYg/0.jpg"> <source src="http://www.youtube.com/v/7QWThlpRpYg?f=videos&app=youtube_gdata" type="application/x-shockwave-flash" /> <source src="rtsp://v5.cache1.c.youtube.com/CiILENy73wIaGQmIpVFahpMF7RMYDSANFEgGUgZ2aWRlb3MM/0/0/0/video.3gp" type="video/3gpp" /> <fallback> <p><span>You cannot watch videos</span></p> </fallback> </media> </div> </section> </body> </ui> </ideal>
Figure 56. Presentation: Static sources
Now we are going to get a collection of sources by invoking Youtube API. For this case, we have a dynamic set of sources controlled by a data model collection specified by means of the repeat-nodeset attribute.
<?xml version="1.0" encoding="utf-8"?> <!DOCTYPE ideal2> <ideal id="index" title="Youtube"> <resources> <link rel="stylesheet" id="pleasefixStyle" href="pleasefix.css" /> </resources> <ui> <body> <header id="headerSection"> <include content="Foot/generic/foot/header" /> </header> <section id="mainSection"> <div class="vertical center common title.common" title="${video.title.plainText}"> <media id="mymedia" poster="${video.mediaGroup.thumbnails[0].url}"> <source id="mysource" repeat-nodeset="video.mediaGroup.youTubeContents" src="${video.mediaGroup.youTubeContents.current.url}" type="${video.mediaGroup.youTubeContents.current.type}" /> </media> <trigger id="add" class="novalidate accept" value="Añadir" /> </div> </section> <footer id="footerSection"> <include content="Foot/generic/foot/foot" /> <separator class="line" /> <include content="Foot/generic/foot/powered" /> </footer> </body> </ui> </ideal>
Figure 58. Presentation: Dynamic sources
Now we are going to get a video by invoking Youtube API.
public void execute(Context the_context) throws OAException {
// The previous presentation shows a placard with a set of videos
String yid = ContextUtil.getEventParam(the_context, EventsParams.PARAMETER_VALUE);
if (yid != null) {
com.google.gdata.data.youtube.VideoEntry video = YoutubeFacade.query(yid);
if (video != null) {
the_context.setElement("video", video);
}
}
}Figure 59. Application Operation: getting a video