Creating Asha Web Apps with Brunch and Jade

Asha web apps?

Asha web apps are a lightweight application development framework for creating apps for low end Nokia devices (Asha series and earlier). While JME is the most popular technology for creating apps for Asha, web apps are a reasonably quick and convenient way to expose content on the web – basically, your garden variety front ends for restful services, spiced by some simple navigation.

Since Asha devices don’t have local javascript execution, javascript is executed on proxy server. “Normal” web pages execute all javascript on the proxy, but Asha web apps provide some “shortcuts” for doing simple DOM manipulation (add/remove css classes, set values in input fields) without the proxy roundtrip. Check out “MWL” library for details.

Standard workflow

Normally, you use Eclipse to develop and test Asha web apps. Nokia provides the “Nokia Web Tools” IDE for this; it’s a rather mainstream Eclipse based IDE, spiced with webkit based “local” simulator (that runs javascript locally), and the “cloud” simulator that runs Javacript on the real Nokia proxy servers (but still renders the DOM on the webkit based simulator).

While this is fine for most web developers, there are lots of us relentlessly looking to optimize our workflows, to make it little more efficient, little more fun (or more tolerable, depending how bad an aversion you have for Javascript and HTML) and little more readable and maintainable.

For this kind of developer, there are tools like CoffeeScript, Brunch, Jade, SASS, LESS, HAML. In this exposition we’ll use CoffeeScript, Brunch and Jade.

CoffeeScript is a language that compiles to idiomatic and readable/debuggable JavaScript. It makes producing JavaScript more tolerable for people used to modern languages without semicolons, `function` keywords
and a selection of other nastiness that plagues JavaScript.

JADE is a language that compiles to HTML.

This Jade:

        doctype 5
	html(lang="en")
	  head
	    title= pageTitle
	  body
	    h1 Jade - node template engine
	    #container
	      if youAreUsingJade
	        p You are amazing
	      else
	        p Get on it!

Compiles to this html:

<h1>Jade - node template engine</h1>
<div id="container">
 
You are amazing
 
</div>

As you can see, this makes it easier to “see forest from the trees”, as the eye is not misdirected by stream of redundant characters and endless <div>’s.

Brunch is an “assembler” for HTML5 applications. It picks up all the pieces you have (CoffeeScript files, JADE templates, etc.) and produces a runnable web application out of that. It can watch the files on the background, compiling CoffeeScript files to JavaScript the second you save them, running unit tests immediately, refreshing the browser in real time etc.

We use Brunch as the “skeleton” of our Asha web application.

Getting started

Prerequisites: This flow has been tested on Linux and Windows. Have to install Node.js, git, the usual stuff every self respecting web developer has set up on day one. Anecdotal evidence suggests it’s a good idea to compile Node.js from source instead of using the packaged versions, if you are lucky enough to be on Linux.

We clone the basic scaffolding from github and install the dependencies:

 

$ git clone git@github.com:vivainio/awa-brunch.git awa-helloworld
$ cd awa-helloworld/
$ npm install
npm http GET https://registry.npmjs.org/javascript-brunch
npm http GET https://registry.npmjs.org/css-brunch
npm http GET https://registry.npmjs.org/uglify-js-brunch
npm http GET https://registry.npmjs.org/clean-css-brunc
.. etc ..
This install Brunch, CoffeeScript compile and lots of other packages with npm.

Let’s take a look at the project structure:


ville@ville-tp:~/p/awa-helloworld$ tree app
app
├── assets
│   ├── config.xml
│   ├── icon.png
│   ├── index.html
│   └── s40-theme
│   ├── css
│   │   ├── s40-theme.css
│   │   ├── single_landscape.css
│   │   └── single_portrait.css
│   ├── images
│   │   ├── arrow-close.png
│   │   ├── arrow-open.png
│   │   ├── back_40x40.png
│   │   ├── button-bg_40x40.png
│   │   ├── close_40x40.png
│   │   ├── grid_40x40.png
│   │   ├── option-menu_titlebar.png
│   │   ├── refresh_40x40.png
│   │   ├── search_40x40.png
│   │   ├── tab_bg.png
│   │   └── title-bar.png
│   └── js
│   ├── s40-theme.js
│   └── screensize.js
├── index.jade
├── README.md
├── templates
│   └── mainlist.jade
├── testCs.coffee
└── testJs.js

 

Now, we start “brunch watch” that compiles the application in real time as we edit the files, and for added convenience launches a webserver serving on :3333:


ville@ville-tp:~/p/awa-helloworld$ brunch watch --server
26 Apr 22:03:48 - info: application started on http://localhost:3333/
26 Apr 22:03:48 - info: compiled in 115ms
26 Apr 22:03:49 - info: compiled in 206ms

 

The resulting application that we can deploy, or preview in browser, gets generated in awa-helloworld/public directory:

 

ville@ville-tp:~/p/awa-helloworld$ tree public
public
├── config.xml
├── icon.png
├── index.html
├── javascripts
│   ├── app.js
│   ├── templates.js
│   └── vendor.js
├── js
│   └── templates.js
└── s40-theme
├── css
│   ├── s40-theme.css
│   ├── single_landscape.css
│   └── single_portrait.css
├── images
│   ├── arrow-close.png
│   ├── arrow-open.png
│   ├── back_40x40.png
│   ├── button-bg_40x40.png
│   ├── close_40x40.png
│   ├── grid_40x40.png
│   ├── option-menu_titlebar.png
│   ├── refresh_40x40.png
│   ├── search_40x40.png
│   ├── tab_bg.png
│   └── title-bar.png
└── js
├── s40-theme.js
└── screensize.js

 

“Sources” under app/ directory were processed to produce these files; .coffee files were compiled and concatenated to “app.js”, index.jade was converted to index.html, and so on.

There is one extra directory we didn’t show yet, the “vendor” directory:


ville@ville-tp:~/p/awa-helloworld$ tree vendor/
vendor/
├── jade_runtime.js
└── README.md

If you are using JavaScript libraries like jQuery, you would just copy it under vendor/ and all of them get automatically concatenated to vendor.js. This makes the app fast to load as it reduces the amount of separate files to download. For production, Brunch can also minify the Javascript files to further reduce page weight. jade_runtime.js is here to support *precompiled Jade templates*

Shut up and show it running

In the interest of making things as “familiar” and frictionless as possible, we will preview the application in standard Chrome browser instead of Nokia Web Tools. So we launch Chromium and disable web security to prevent CORS from cramping our style and killing our Ajax requests:

	$ chromium-browser --disable-web-security http://localhost:3333

This doesn’t look at all what you would expect on the phone screen, because we haven’t specified a viewport size:

Chromium inspector has a handy feature of overriding the viewport size (Settings -> Overrides -> Device Metrics), so we use it to set the resolution to match Asha Full Touch devices (240 x 400):

Now, we have a low-fidelity representation of the phone experience! While this certainly wouldn’t satisfy an UI designer, it’s sufficient for a busy software developer that mostly needs to focus on the “logic” side of the web app.

Launching in NWT

Now is the time to get this running with “real” IDE, i.e. Nokia Web Tools. Launch NWT, do File -> New -> Import web app, select public/config.xml and launch the application in local preview:

Is this it?

There is more to show: how to utilize precompiled templates, how to inject the MWL library, and how Jade can help you create MWL UI “components” with reusable, encapsulated logic. These, and other things to smoothen the development flow will be covered in another blog post, as this already got way too long.

Make a Map Mashup

To go along with this article on the Nokia Conversations Blog, today, we’re going to look at a simple example of a HERE map mashup. This is aimed at people familiar with at least the basics of HTML and JavaScript.

The map mashup (a.k.a. Location Application/Mapplication/MapHack…) we’re going to build combines the HERE JavaScript API with the Flickr API to display a heatmap of the most popular locations for photographs in an area. You could also use this when planning a trip to a new city to find the ‘must-see’ photo ops. We’ll get into the code in a moment but here’s what we’re going to build:

Flickr Heatmap

Before getting started, you’ll need to register with the Developer Portal and get your own App ID and Authentication Token. It should just take a couple of seconds. Less than a minute, definitely. We’ll wait.

Boilerplate

As with all good projects, it’s useful to have a jumping off point that gets all the boilerplate code out of the way so we can dive straight in as quickly as possible.

This file contains all the things you need to get started using the HERE API

HERE JavaScript API Boilerplate

Download it, open it in your browser and you’ll see the map.

Once we’ve created a map, we try and determine the user’s location. This functionality isn’t supported by older versions of Internet Explorer but recent versions of all the browsers allow the user to decide whether or not to share their location with the web page. If we don’t manage, we’ll just display the map in a default location (the HERE office in Berlin).

if (navigator.geolocation) {
    navigator.geolocation.getCurrentPosition(foundLocation, notFoundLocation);
} else {
    notFoundLocation();
}

If we get the location, set the map center to that

map.setCenter(location.coords);

Give me all you’ve got

Now we have a map and it’s centered on the user, it’s time to ask Flickr for images. You’ll need to sign up with Flickr to get your authentication token with them, too.

We can make a request to Flickr that returns the 500 most recent photos around a certain point. To do this we make an AJAX call to:

http://www.flickr.com/services/api/explore/flickr.photos.search

With our API key and the map centre latitude/longitude. In this request, we also need to specify the parameters &extras=geo to ensure that Flickr will return the location tags for the image.

We’re using jQuery in this demo so the code to make the request to Flickr looks like this:

var apiCall = $.get('http://api.flickr.com/services/rest/?method=flickr.photos.search&api_key={YOUR_API_KEY}&min_upload_date=1356886856&lat='+map.center.latitude+'&lon='+map.center.longitude+'&extras=geo&format=json&per_page=500&nojsoncallback=1')
    .done(function(data) {
        // Other stuff
    });

Note: if this doesn’t return anything or you get an error in your JavaScript console about cross-origin problems, you’ll need to view the demo via a local server. To avoid this check out our previous article “Quick Tip: Simple Servers

Heatmaps

When the data comes back from Flickr, we need to format it in a way the Heatmap Overlay can process. There are two types of heatmap visualisation available using the API – ‘density’ and ‘value’. By default, a density heatmap will highlight areas where there are more items closely together while a value heatmap will highlight areas where the values are higher. For example, if there are a lot of cheap houses for sale in the north of a city and one expensive house for sale in the south, a density heatmap would highlight the north while a value heatmap would highlight the south. The difference is between “How much?” (value) and “How many?” (density).

We loop over the photos returned by Flickr:

var heatMapData = [];
if(data.photos && data.photos.photo) {
    for(var i = 0; i < data.photos.photo.length;i++){
        heatMapData.push({
            "latitude": data.photos.photo[i].latitude,
            "longitude": data.photos.photo[i].longitude
        });
    }
}

We’re going to use density here to show where most people take photos so the heatMapData array only contains objects with latitude and longitude.

With the Heatmap Overlay object, we could modify the colours any way we like so that the popular areas show green while the unpopular ones are pale yellow or have them range between neon blue and pink but we’ll stick with the default rainbow colour scheme.

function addHeatMap(heatMapData) {
    // First, delete any previous heatmaps
    map.overlays.clear();
 
    var heatmap;
    // Create the Heatmap
    heatmap = new nokia.maps.heatmap.Overlay({
        // This is the greatest zoom level for which the overlay will provide tiles
        max: 20,
        // This is the overall opacity applied to this overlay
        opacity: 0.8,
        // Defines if our heatmap is value or density based
        type: "density",
        // Coarseness defines the resolution with which the heat map is created.
        coarseness: 2
        });
 
    heatmap.addData(heatMapData);
 
    // Rendering the heat map onto the map
    map.overlays.add(heatmap);
}

Once we’ve added the data to the heatmap, we add the heatmap to the actual map (the map.overlays.add(heatmap) line above). Areas where lots of photos have been taken show in orange and red while areas with fewer photos are pale yellow. We can now see at a glance where the most popular places for photos are.

Check out the finished map

The full source for the FlickrHeat demo is available on GitHub along with our other examples.

Other maps

We can easily do the same mashup using other APIs.

Instagram Heatmap

This is exactly the same as the Flickr example but with the Instagram API instead. This would be handy to highlight areas where people are hanging out.

Neighbourhood Hangouts

Use the Foursquare API and heatmaps to visualize on the map the areas where your neighbors like to hang out and the spots that people like the most in your neighborhood.

SoundScape

Note: this requires a modern browser that supports the Web Audio API

This little application uses the Web Audio API together with the concert information available from the Last FM API to create an immersive, directional soundscape of a city. Fly around and discover the sounds of upcoming gigs. Best with headphones.

This video gives some technical insight into the Soundscape demo

Measuring the speed of resource loading with JavaScript and HTML5

This is a follow up article to Measuring site performance with JavaScript on mobile, I suggest you read it before you continue. In the previous article I talked about the Navigation Timing spec, here I will talk about the Performance Timeline and Resource Timing specs and how they work in IE10, the first browser to implement them. I created a page that shows some of the data available and a library that generates a HAR that you can later analyse.

Continue reading

Using Places API (extra feature: geolocation)

In the earliest version of the application, I was using a hard
coded location (Pariser Platz in Berlin) for the search, however this made the
application quite useless, unless you were looking for places near Pariser
Platz.


So GPS Positioning was the first of the things that I thought of improving
after the Meeting Point application was more or less working.
The idea was to use the phone GPS to get the current location of the phone, and
then start every search for places in this current position.



To achieved that we needed two things:



- The geolocation  API of platform services



- The searchCenter property of the SearchBox.



The idea was pretty simple, we just had to get the position
using the API, put it in the right format and give it to the SearchBox, using
it’s searchCenter attribute. The following code does all this:

var position
= {latitude: 52.516274,longitude: 13.377678}; //default position is Berlin

// callback function for geolocation.
function fillPositionFromGPS(pos)
{
    //
position coordinates
    var
lng = pos.coords.longitude;
    var
lat = pos.coords.latitude;
       position
= {  latitude: lat, longitude: lng };
       alert("geolocation set
to: "
+lng+"  ; "+lat);
}

function getPosition()
{
     
       try
       {

              so
= nokia.device.load("geolocation");
              try {
                  // timeout at
60000 milliseconds (60 seconds)
                  var
options = {timeout:60000};
                  // get the
current position
                  so.getCurrentPosition(fillPositionFromGPS, errorCB, options);
             
}
              catch(e) {
                  alert(extraDebug(e));
             
}
       }
       catch(e){
              alert("cannot load geolocation service"+extraDebug(e));
       }
}

var sb
= new
nokia.places.SearchBox({
         targetNode: ‘searchContainer’,
         template: ‘nokia.mobileHTML5.searchbox’,
         locale: ‘en-gb’,
         suggestions: {
             showAddress: true
         },
         searchCenter: function
() {
             return position;
         },
         onResults: onResults
});

 

 

You can see that, in case the geolocation
doesn’t work or while we are waiting for an answer (as it’s an asynchronous
call we are doing), we are positioned by default in Berlin.
Note also that we can’t pass the position attribute directly to the SearchBox
searchCenter, we need a function that returns an object with the position
coordinates.
Both the geolocation API and the Places API use the coordinates in
international system. So everything just fits perfectly and we don’t have to
worry about any conversion.

 

 

Using Places API (Part III: WRT issues and App demo)

In this post I will talk mainly about the part that gave me
the worsts headaches when coding the application:  Platform Services 2.0.
While I was coding the place search and selection (using Places API) everything
was more or less progressing smoothly, but when you need to access the phone
things get a bit messy.

When you start programming using Nokia WDE, one of the first
things you notice is that there is no way of debugging Symbian WRT applications
when using the simulator.
For example: you can’t put breakpoints to see the variable values. So you have
to debug “old style” using alerts and your own var_dump functions.

While you don’t use the phone services, you can just run
your webApp on your web browser and debug it as any other. But this comes to an
end the second you start using in your code the Platform Services functions to
access the phone.

So to debug I often use this var_dump function that I found
somewhere online. I just changed a little bit the code to suit my needs:

function inspect(obj, maxLevels, level){

    var
str = , type, msg;
    //
Start Input Validations
    //
Don’t touch, we start iterating at level zero

    if
(level == null)
        level
= 0;
 
  
// At least you want to show the first level

    if
(maxLevels == null)
        maxLevels
= 1;
    if
(maxLevels < 1)
        return ‘<span
style="color:red;">Error: Levels number must be >
0</span>’
;
    //
We start with a non null object
    if
(obj == null)
        return
‘<span style="color:red;">Error:
Object <b>NULL</b></span>’
;
    //
End Input Validations
   
    // Each
Iteration must be indented
    str
+= ‘<ul
style="list-style:circle;padding:15px;">’
;

    // Start
iterations for all objects in obj
    for
(property in obj) {
        try {

            // Show
"property" and "type property"
            type = typeof(obj[property]);

            str
+= ‘<li
>(‘
+ type
+ ‘) ‘ + property +
            ((obj[property] == null) ? (‘: <b>null</b>’) : ()) + ((type != ‘object’) ? (‘: ‘+obj[property]) : ()) +
            ‘</li>’;

            // We keep
iterating if this property is an Object, non null
            // and we are inside the required number of levels
            if ((type == ‘object’) && (obj[property] != null) && (level + 1 < maxLevels))

                str
+= inspect(obj[property], maxLevels, level + 1);
        }

        catch
(err) {
            // Is there some properties in obj we can’t access? Print
it red.
            if (typeof(err) == ‘string’)

                msg
= err;
            else
                if (err.message)
                    msg = err.message;
                else
                    if (err.description)
                        msg = err.description;
                    else

                        msg = ‘Unknown’;

           str
+= ‘<li><span
style="color:red;">(Error) ‘
+
property + ‘: ‘ + msg + ‘</span></li>’;

        }

    }   

    // Close indent
    str
+= ‘</ul>’;   
    return
str;
}

 

I had some other issues
with the Platform Services (2.0  version),
the most important being that the Contacts API doesn’t seem to work at all in
the latest version of Symbian (Symbian Anna). 

For those who also
encounter issues with PS 2.0, it seems the official recommendation is to switch
to the old version, the PS 1.0 (as
said here
). Unfortunately it didn’t work in my case, just loading the 1.0 Contacts
API instantly crashed the application.

For that reason I
developed a version of the application getting the Friends list from the
outgoing calls log, instead of the phone contacts.

I put the code here:

Contacts version

 

//Gets the contacts list using
platformservices 2.0
function showContacts()
{
    try
{
       cal
= nokia.device.load("contacts");    
       try{
              if (typeof contacts
== "undefined") nokia.device.load("contacts");
              var
transactionID =
cal.getContacts(result_contacts,null,null,errorCB);          
      
}
       catch(e){ errorCB(e); extraDebug(e);}   
   
}
    catch
(e) {alert("cannot load contacts service"+extraDebug(e));}
}

//Success callback function for
the getContacts call
function result_contacts(outPut)
{
    var
entry = null;   
    try
{
        eligible_contacts
= new
Array();
        while ((entry = outPut.next()) != null) {
            //I keep the contacts in a list.
            eligible_contacts.push(entry);
        }
        selected_contacts
= new
Array();
        showEntryList(eligible_contacts, false, false);      
    }

    catch(err){extraDebug(err);}   
}

Call Logs version

 

//Gets the contacts using the log of outgoing calls, currently without Date
restriction.
function callLog(){
    if
(eligible_contacts
=== null) {
              alert("using outgoing calls log to fill the friends
list"
);//we
only alert the first time
              try {

                     var
commlog = nokia.device.load("commlog");
                     // Retrieves the specified number of logs.                          
                     var transactionId
= commlog.getList(showLogContatcs, {
                           type: "CALL",
                           flag: "OUTGOING"
                     }, errorCB);
             
}
              catch (e) {alert(e.toString());}
      
}     
}

//callback function for commlog, it fills the eligible_friends list with
the numbers retrived from your call log.
function showLogContatcs(outPut)
{
       var
entry=null;
       var
log;
       var
i=-1; // used for the id of the entry.
       try
{
        eligible_contacts
= new
Array();
        while ((log = outPut.next()) != null) {
            entry = new Object();
                     entry.id=i;
                     entry.tel= new Object();
                     entry.tel.mobile=log.phoneNumber;
                     entry.name= new Object();
                     entry.name.first=log.contactName;
       //I keep
the contacts in a list only if they are not repeated. In that case I keep the
one with name.
                     keepLogEntry(entry);      

                     i–;
        }

        selected_contacts
= new
Array();
        showEntryList(eligible_contacts, false, false);
    }

    catch(err){ extraDebug(err);}
}

 

Another bug appeared using the 2.0 Contacts API (in Symbian
older than Anna),  when iterating through
the results, but as it might be due to the phone I was using I will not dwell
into details, if you are interested look at this post
for more information.

However, after all the headaches were solved I finally had
the application up and running. Here I leave you some images to see how it
looks:

IMAGE 1: Here you can search for a place, either by category (like
restaurants or shops) or directly by name in the searchbar. Assume that we clicked the restaurants category.

IMAGE 2: After that, you look in the results and choose a place of
your liking, by clicking on it.

IMAGE 3: Here you take a detailed look at the place
that you chose and click on the "meet" icon to select this place as the
meeting point.

IMAGE 4: Then you choose the people that will be attending the meeting
(form your contacts  list or call log
depending on the version).

IMAGE 5: You pick a time for the meeting. And press the “Create
Meeting” button. Then the application will create an event in your phone calendar, also
an iCalendar file that will be attached to the MMS message sent to all the
numbers you previously choose.

IMAGE 6: Finally if all went well you’ll see a summary screen like
this.

Using Places API (Part II: the Coding)

After designing the application and collecting all the
components, it was time to code. But with the coding came the first
difficulties. The very first being a bug in the platform services 2.0. The
application would instantly crash when using both Platform Services and Places
API together.

There are two ways to avoid this:

Short
way:  just include the platform services
library before you include the Places API library. Like this:

 

      <script type="text/javascript" src="script/platformservices.js" charset="utf-8" ></script>

      <script
type="text/javascript"
src="http://api.maps.ovi.com/places/alpha3/jsPlacesAPI-en_GB.js"></script>

 

Longer way (better): you will correct the bug in the library. Look for
the initialitzation of the nokia.device object at the beginning of the library.

 

Replace this line:  if((typeof nokia.device)!="undefined")

For
this other line: if((typeof nokia.device)=="undefined")

After either one of those options, the library should work correctly.

For the Meeting Point application, I just needed the
Searchbox template (to search for a place), the placeList template (to display
the results) and the Place template (display the chosen meeting place)
My first idea was to use the default Places API templates, but when I displayed
them on the mobile phone they didn’t look nice and lots of elements were not in
the appropriate size.

Luckily I had one coworker developing some Places API
templates for mobile phones, so I took his work for my application :P (you can
see the code below)

For the searchbox and the placelist the default mobile
template was perfect for me.  Below there
are the template definitions, and the UI widgets declarations.

          PLACELIST
TEMPLATE

       
<div module="List">

            <ul each="{results[].place}"
rel="list-data" class="nokia-place-list">

                <li class="nokia-place-list-elem"
rel="nokia-place-item">

                    <img url="{categories[0].iconURL}"
class="nokia-place-category">

                    <div class="nokia-place-list-elem-content">

                        <p fill="{name}"
rel="nokia-place-name" class="nokia-place-name"></p>

                        <div class="nokia-place-address">

                            <span fill="{street()}"></span>, <span fill="{locality()}"></span>

                        </div>

                        <div tpl="nokia.general.rating"
if={placeId} class="nokia-places-mobile-rating-widget"></div>

                    </div>

                </li>

            </ul>

            <div rel="list-pagination"></div>

        </div>

           SEARCHBOX
TEMPLATE

       
<div module="SearchBox"
class="nokia-searchbox">

            <div class="nokia-searchbox-input-wrapper"
>

                <input class="nokia-searchbox-input"
type="text" rel="searchbox-input"/>

            </div>

            <input class="nokia-searchbox-button"
type="button" rel="searchbox-button"
value="Search"/>

            <div rel="searchbox-list"
class="nokia-searchbox-list">

            </div>

        </div>

Here you can find the
css file for the templates: ovi-places-mobileHTML5.css

 

 

        var placeList
= new
nokia.places.PlaceList({

               targetNode: ‘placeListContainer’,

               template: ‘nokia.mobileHTML5.placelist’,

               perPage: 100,

               locale: ‘en-gb’,

              
events:
[ {

                   rel: 'nokia-place-item',

                   name: 'click',

                   handler: function(jsonObject){

                       if
(jsonObject.placeId) {

                           place.setPlaceId(jsonObject.placeId);                               

                       }else{

                           place.setData(jsonObject);

                       }               

                       pageController("selectPlace");

                                 

                   }

               }]

           })

           var
onResults =
function(data){

                            placeList.setData(data);

                     searchType = "placelist";

                     showSearchPlace();

           }

 

         var
sb = new nokia.places.SearchBox({

               targetNode: ‘searchContainer’,

               template: ‘nokia.mobileHTML5.searchbox’,

               locale: ‘en-gb’,

               suggestions: {

                   showAddress: true

               },

               searchCenter: function
() {

                   return
position;

               },

               onResults: onResults

           });

As you can see the mobile templates are pretty much the same
as the “normal” templates, it’s the css that has the major changes.
Note also, that to use the mobile templates, I declare the UI Widgets in the
standard way, and the only thing that I need to change is the template
parameter.

I also wanted my application to erase the text on the
SearchBox when on the search page and the back button is pressed.
To achieve this small change you need the following piece of code:

 

function previousPageKey()
{
       if (actual == "searchPlace") document.getElementsByClassName(‘nokia-searchbox-input’)[0].value = "";   

}

 

function init(){            

window.menu.setRightSoftkeyLabel(‘Back’,
previousPageKey);

}

-       To change the behavior of the Back key in
Symbian you need to use this line of code:

window.menu.setRightSoftkeyLabel(‘Back’, previousPageKey);

As you also have to define the function
that will be triggered when the Back key is pressed.
more info

-      To know how to select the input field in the
searchBox. The quickest way is to use firefox + firebug and explore the html
content or use the html explorer of the simulator.

The
next step was to adapt the mobile place template, because I needed it to do
some specific things for my application. To be precise I wanted to add a button
for creating a meeting in the selected place.

You
can see the code for my mobile place template here:

<script id="mobilePlaceWidget"
type="text/template">  

<div tpl="nokia.mobileHTML5.map"
class="nokia-place-right"></div>

<div tpl="nokia.mobileHTML5.name" class="nokia-place-header"></div>

 

 

<div class="nokia-place-header
nokia-places-mobileHTML5-menu"
>

       <div class="nokia-place-menu">

              <ul>

                     <li class="nokia-place-menu-element
nokia-place-menu-phone"
>

                           <a url="{primaryPhoneCall()}">Call</a>

                     </li>

                     <li class="nokia-place-menu-element
nokia-place-menu-share"
>

                           <a url="{primaryPhoneSMS()}">Share</a>

                     </li>

                     <li onclick="pageController(‘selectFriends’);" class="nokia-place-menu-element
nokia-place-menu-route"
>

                           <a>Meet</a>

                     </li>

                     <li class="nokia-place-menu-element
nokia-place-menu-web"
>

                           <a url="{primaryURL()}">Web</a>

                     </li>

              </ul>

       </div>

</div>

 

     

<div tpl="nokia.mobileHTML5.gallery" class="nokia-place-header"></div>

 

<div if="{businessInformation.openingHours}">

    <p c

Using Places API (Part I: the Thinking)

After getting a little familiar with Places API,
it was time to put the
api to good use. So I came up with a simple idea, that would also bring
me for
first time to mobile phone applications. In this post and the two
following  ones I will tell you how I easily turned this "simple idea"
into a really nice app.

So, I wanted to create a Meeting Point application for
Symbian phones. The outline of the application would be very simple:

1-     
Search and choose a place for the meeting

To do that I could use Places API:

-         
A SearchBox and a Placelist templates for
searching.

-         
A Place template to choose the place.

2-     
Choose the friends you want to meet

The possible friends would be the list of the contacts in the phone.

3-     
Select a time for the meeting.

4-     
Create the meeting.

In your own phone: create an iCalendar event

Share
it: sending an MMS message to all the selected friends with the iCalendar event
attached.

 

The first difficulties came when I was looking on how I
would access the phone, because if you remember, Places API runs on a web
browser, so I needed this application to be a webapp. But could webapps access
the phone?
Luckily my coworkers pointed me to Nokia Web Developing and
there I found the answer: the nokia
WRT widgets
and the Platform Services library .

The WRT widgets are (quoting Nokia): "a type of Web application in which the HTML,
CSS and Javascript files are packaged and installed locally on the device
instead of being hosted on a remote server
".
So essentially they’re like a web application but you have to install it and
run it locally with the Symbian WRT (Web Runtime). More
info

Platform Services is a JavaScript API that allows you to
access the phone services through the WRT, so you can use these services when
programming widgets.

With those two things I had my main problem solved, I could
create a webapp with access to the phone, but I found one last thing in the
Nokia page: a developing environment. It is specifically for Symbian web
applications, the Nokia
Web Tools
, is based on Eclipse, so if you have ever used it you’ll feel
like home. The great thing is that it comes with a simulator to test your
mobile applications before deploying them to an actual phone.

So I had Places API, the Widgets + platform services and the
development environment, I was all set to start.

 

More Places API: Headless API and UI Widgets

If you went through the developer’s guide, you might have
come across two types of JavaScript objects, they can cause a little bit of
confusion, especially the ones with the same name (like the two Place objects), although they are in different namespaces. So let’s
take a look at the two types:

Headless API
objects
: They are the ones with the information (the data) that
will be displayed. There are mainly three of them: Place,
Media
and Review.

And you’ll receive them as jSon objects, so when you read something about data,
or about a jSon object we are referring to one of these objects.

In the documentation you can see other objects in the
Headless API, but they are essentially combinations of these three.

Now that we know them, let’s use them:

This piece of code will put the names of every place we get
from the search. The search will be run around the searchCenter (Berlin in this
case), and with the term that we provide (pizza in this case). You can change
the location and search term as you please.

<div id="results"></div>

<script>

        var term="pizza";

       

        var searchCenter = {

                    latitude: 52.516274,

                    longitude: 13.377678

                }; //Berlin   

       

       

        nokia.places.searchManager.findPlaces({

            searchTerm: term,

            onComplete: function(data, status){

                // data is an array of searchResult objects

                var content = "<ul>";

                for(i in data.results)

                        content+=
"<li>"+
data.results[i].place.name;

       

                content+="</ul>";

                document.getElementById("results").innerHTML=content;

            },

            searchCenter: searchCenter

        });

</script>

 

Like it’s said on the documentation the search
results
are just an array of objects with two elements in each object:  distance, and the previously mentioned Place
object, that holds the information for each place that the search has found.
As you saw the headless API just gives you the raw data, so the format and
behavior of the final web page had to be coded by us, although in this example
it was only adding a list of names, you can complicate it as much as you want.

Finally we can take a look at the Place object. But rather
than looking through the documentation sometimes is better to “see” the object
for yourself.

To see an example of the place
object use the “load data” on the Headless
API data fetch
example and you will see the full detail of the object
corresponding to the headless API Place object.

post 2 image 1

 

 

In my case this headless data fetch example has been
surprisingly useful, it can ever be faster than using the console.log on
firebug, and setting a break point, I hope you’ll find it useful too.

The other type of JavaScript objects are the UI Widgets:

UI
Widgets
: these objects are in charge of rendering. Essentially, they will
render (the data) somewhere in your web page (target element) ,
and they will do it in a certain way (template).

UIWidget ->  RENDER (data,
target, template);

The data will be one of the previously mentioned Headless
API objects.

The target can be any html element.

The template might be the more confusing thing here. It is
used to tell the widget how to render the data, by “how to” meaning the html
structure that will show up in the final web page.

There are three of them: Place,
PlaceList
and Searchbox.
And are the ones that you see all the time declared in the getting started and
developer’s guide examples. A note: actually each one is a subclass of the  Widget object.

As I told you before, we have two kinds of place objects, so
it’s important to know if we’re dealing with the headless API object or the UI
Widget in order to avoid confusion.
Here are examples of definition for both Place objects:

Headless API:

var pp = new nokia.places.objects.Place();

UI Widget:

 

 

var pp = new nokia.places.Place ({        targetNode: 'detail',        template: 'reviewsAndGallery',        events: [           {              rel: 'eventGal',              name: 'click',             handler: function (jsonObj) {pp.setPlaceId(jsonObj.placeId);}         }       ] });

Usually you’ll only need to declare the UI Place Widget
objects, because the Headless API Place objects will be given to you by the
Headless API.

 


Getting started at Places API

The first day in my Nokia internship was also my first contact with Places API, and my task was to use
the first week to “get to know each other”, so that’s what I did. The best way
to achieve it is to read both, the getting
started
guide and the developer’s guide,
this last one at least until the attributes section, the following parts you
can leave them for later, when you get more familiar with the API.

After a first glance in the documentation you can see that
there are two big parts in the Places API:
The first is called the Headless API”some
functions to access the Nokia servers and make searches and queries and for the
raw information about places.

The second are the templates:
the cool stuff! With them you can put everything that the API has quick and
easily in your web page, and it will look really nice! Well, more or less quick
an easy, we’re not talking about drag and drop here. It’s more like copy-paste
the code, then do some small tweaking and “voilà”!
To do that, you don’t need much, in my first contact I had this in my pocket: a
basic level of html, a very basic level of css, and almost 0 level on
javascript. And I managed pretty much everything. Although I have to say, that
due to my lack of javascript when I wanted to do more complicated things than
the ones in the developer’s guide, I advanced very slowly.
So don’t be scared, you don’t need to learn a whole new programming language to
use the API, apart from the basic web knowledge (html+css+javascript), you just
need to get familiar with this thing called “templates” and its “attributes”
and you’re ready to go.

If you decide to start with Places API, my advice is that
when following the developer’s guide, you shouldn’t just read it, but also copy
the code examples in your own test webpage to see that is working. You don’t
need to download anything to use the API, just a web browser and internet
connection is enough.

Some examples will require you to make small changes in the
code to make them work. For example in the “A
custom template
  section, to use the
custom template you will need this piece of code:

var place = new nokia.places.Place({
    template: "myTemplate",
    targetNode: "renderMyTemplateHereId"
});
place.setData (object);
 
<script id="myTemplate" type="text/template">
<div>     <p fill="{name}"></p>     <p fill="{fullAddress()}"></p>
    <ul each="{media[supplier.name=='orange']}">
      <li fill="{URL}"></li>     </ul>
</div> </script>

 

But, for it to work you need to declare the object variable
used in place.setData (object).You
can just use the object defined at the beginning of the section, like this:

var object = {
    name: 'Le Marfil',
    contact: {
        description: 'Home away from home'     },     location: {         address: {         … };

Or you could also use some standard place object. To do that
change the

		place.setData(object);

For the following line:

      place.setPlaceId('250u09tv-fc09ac6bdbe340e9b5e2ad78efc814d0');

That will get an object with all the place information, you
can change the placeId with any other valid one of your liking (get them here).

As you see, it’s with small tweaking like that you and the
API will start to “get to knodw each other” :P