Advertisement

Introduction to webOS SDK Development: Part 4

by

This Cyber Monday Tuts+ courses will be reduced to just $3 (usually $15). Don't miss out.

This post is part of a series called Introduction to webOS SDK Development.
Introduction to webOS SDK Development: Part 3
Introduction to webOS SDK Development: Part 5

This is the fourth installment of our webOS introduction series. In this tutorial, you will learn how to use the webview widget in webOS to display a website embedded in your app. We'll also add functionality to allow list item reordering and deleting.

The WebView

To begin, go ahead and generate a new scene called article:

palm-generate -t new_scene -p "name=article" tutsplus

Next, edit app/views/article/article-scene.html to contain the following:

<div id="myHeader" class="tuts-header palm-page-header multi-line">
    <div id="titleImage" class="title-image"><img src="images/tutsplus.png"><span class="main-title">Skills to pay the bills</span></div>
</div>

<div id="webWrapper">
  <div x-mojo-element="WebView" id="myWebView" class="WebClass"></div>
</div>

We use the same header as in our main scene. Below that we add the webview widget. Note that we wrap the webview into a wrapper-div, that way
we can push the webview down below the header.

Add the additional class to stylesheets/tutsplus.css.

#webWrapper {
    padding-top: 48px;
}

Next edit app/assistants/article-assistant.js and add the setup of the webview widget:

ArticleAssistant.prototype.setup = function() {
    /* this function is for setup tasks that have to happen when the scene is first created */
	
    /* use Mojo.View.render to render view templates and add them to the scene, if needed */

    /* setup widgets here */

    /* add event handlers to listen to events from widgets */
	        
    this.controller.setupWidget("myWebView",
        
        this.attributes = {
            url: this.url,
        },
        
        this.model = {
        }
    ); 
};

Also add the necessary code to pass the url to the scene:

function ArticleAssistant(url){
    /* this is the creator function for your scene assistant object. It will be passed all the 
       additional parameters (after the scene name) that were passed to pushScene. The reference
       to the scene controller (this.controller) has not be established yet, so any initialization
       that needs the scene controller should be done in the setup function below. */
       
       this.url=url;

}

As soon as the article scene is called with a url, the webview widget starts to load the website contents.

We also need to change our list scene to call the new article scene when we tap one item. Edit app/assistants/list-assistant.js for that
and add the function handleTap:

ListAssistant.prototype.handleTap = function(event) {
    Mojo.Log.info("Event index is: " + event.index);
    Mojo.Log.info("selected: " + event.item.guid);
    Mojo.Controller.stageController.pushScene("article", event.item.guid);
}

The list's model contains the property guid, which is a url to the website. Using the event object we get the guid of the tapped
list item and pass that to the article scene.

Also add a list taphandler to the activate function of the ListAssistant:

    this.tapHandler = this.handleTap.bindAsEventListener(this);
    Mojo.Event.listen(this.controller.get('MyList'),Mojo.Event.listTap, this.tapHandler);

Don't forget to cleanup your listener in the deactivate function:

ListAssistant.prototype.deactivate = function(event) {
    /*  remove any event handlers you added in activate and do any other cleanup that should happen before
        this scene is popped or another scene is pushed on top */
        
    Mojo.Event.stopListening(this.controller.get('MyList'),Mojo.Event.listTap, this.tapHandler);
    
};

That's it for the webview. Package, install, and run the app:

List Item Reordering/Deleting

Wouldn't it be nice if you could change the order of the tutsplus sites in the first scene? Say you want Mobiletuts+ first instead of nettuts, or what if you want to delete a site you aren't interested in? I'm going to show how to do that with some built-in list functionality and cookies.

If you read part 2 of this series, we supplied the data for the list from a static model. Let's change that to use a dynamic model. Open app/assistants/main-assistant.js:

in the setup-function, replace:

  this.myListModel = { items : [     
    { title : 'Nettuts', titleImage : 'images/nettuts.png', leftImage : 'images/tiny-net.jpg', col : '#2e6a60'},

with

  this.myListModel = { items : [] };

This will supply an empty list model at setup time for the list. Also change the list attributes:

  this.myListAttr = {
    itemTemplate: "main/itemTemplate",
    swipeToDelete: true,
    renderLimit: 20,
    reorderable: true
  };

As you can see, we added the swipeToDelete and reorderable properties and set them to true. This will enable list reordering and item deleting.

Next, let's edit the activate function and add some functions to save the sort-order and displayed tuts-sites. To do that, we need to add a cookie to the app. First, the cookie 'TutsPlusCookie' is defined and loaded:

MainAssistant.prototype.activate = function(event) {
	/* put in event handlers here that should only be in effect when this scene is active. For
	   example, key handlers that are observing the document */

  var myCookie = new Mojo.Model.Cookie('TutsPlusCookie');
  var cookieData = myCookie.get() || '';

If the cookie does not exist yet, we define its initial content and save. If the cookie already exists, we load the data from it:

  if (cookieData == '') {
    myCookie.put({ tutsdata: '|1|2|3|4|5|6|7|8|9|' });
    var tutsdata='|1|2|3|4|5|6|7|8|9|';
  } else {
    var tutsdata=cookieData.tutsdata;  
  }

Let me explain the contents of the cookie for a moment. Every tutsplus site has a defined id (from 1 to 9). The character "|" is used as a delimiter between those ids. The tutsdata variable defines the sort order of the sites as well which sites are shown. The default value shows the initial sort order and also defines that all 9 sites will be displayed. You'll see later how the reorder and delete functions will manipulate that data and store it back in the cookie.

We also need to define and add two additional listeners, one for the ListReorder and one for the ListDelete Event. We also add a function to load the data into the list model.

  this.loadData(tutsdata);

  this.tapHandler = this.handleTap.bindAsEventListener(this);
  this.reorderHandler = this.handleReorder.bindAsEventListener(this);
  this.deleteHandler = this.handleDelete.bindAsEventListener(this);

  Mojo.Event.listen(this.controller.get('MyList'),Mojo.Event.listTap, this.tapHandler);
  Mojo.Event.listen(this.controller.get('MyList'),Mojo.Event.listReorder, this.reorderHandler);
  Mojo.Event.listen(this.controller.get('MyList'),Mojo.Event.listDelete, this.deleteHandler);

}

Don't forget to stop all listeners when the scene is deactivated:

MainAssistant.prototype.deactivate = function(event) {
  /* remove any event handlers you added in activate and do any other cleanup that should happen before
	 this scene is popped or another scene is pushed on top */

    Mojo.Event.stopListening(this.controller.get('MyList'),Mojo.Event.listTap, this.tapHandler);
    Mojo.Event.stopListening(this.controller.get('MyList'),Mojo.Event.listReorder, this.reorderHandler);
    Mojo.Event.stopListening(this.controller.get('MyList'),Mojo.Event.listDelete, this.deleteHandler);
};

Let's have a look at the new this.loadData function:

MainAssistant.prototype.loadData = function(tutsdata) {

  var newData = []; 
  var k=0;
 
  this.data = { items : [     
	{ id: 1, title : 'Nettuts',  titleImage : 'images/nettuts.png', leftImage : 'images/tiny-net.jpg', col : '#2e6a60' },
	{ id: 2, title : 'Vectortuts', titleImage :'images/vectortuts.png', leftImage : 'images/tiny-vector.jpg', col : '#19487e' },
	{ id: 3, title : 'Psdtuts', titleImage : 'images/psdtuts.png', leftImage : 'images/tiny-psd.jpg', col : '#a51500' },
	{ id: 4, title : 'Activetuts', titleImage : 'images/activetuts.png', leftImage : 'images/tiny-active.jpg', col : '#a5290a'},	
	{ id: 5, title : 'Aetuts', titleImage :'images/aetuts.png', leftImage : 'images/tiny-ae.jpg', col : '#4a3a57'},
	{ id: 6, title : 'Cgtuts', titleImage :'images/cgtuts.png', leftImage : 'images/tiny-cg.jpg', col : '#73434f'},
	{ id: 7, title : 'Phototuts', titleImage :'images/phototuts.png', leftImage : 'images/tiny-photo.jpg', col : '#2e92b2'},	
	{ id: 8, title : 'Audiotuts', titleImage :'images/audiotuts.png', leftImage : 'images/tiny-audio.jpg', col : '#3d6b00'},
	{ id: 9, title:  'Mobiletuts', titleImage: 'images/mobiletuts.png', leftImage: 'images/tiny-mobile.png', col : '#d19c00' }
  ] };

First, we define the 9 tutsplus sites, this is unchanged from Part 2, when we defined a static list. One change: we added the id as noted above. We then loop through the passed in string of which sites to show and how they are ordered. Each sites that is going to be displayed is added to a new array, this will be our new contents for the list model:

  
  var temp=tutsdata.split('|');
  
  for (var i=1;i < temp.length-1;i++) {
    for (var j=0;j < this.data.items.length;j++) {
      if (this.data.items[j].id==temp[i]) {
        newData[k] = { id: this.data.items[j].id, title: this.data.items[j].title, titleImage: this.data.items[j].titleImage, leftImage: this.data.items[j].leftImage, col: this.data.items[j].col };  
        k++;
      }
    }
  }

At last, we pass the new data to our (empty at setup) list model and tell the model that the data has changed (modelchanged). This is the same technique that we used in Part 3:

  
  this.myListModel["items"] = newData;  
  this.controller.modelChanged(this.myListModel , this);
}

The last two things missing are the functions for the ListReorder and ListDelete event. Let's start with the handleReorder event, which will get called every time the list is reordered.

With help from the passed in parameters event.item, event.toIndex, and event.fromIndex, we change the lists model to reflect the new sort order. A new cookie value is then constructed out of the model and saved into our app's cookie.

MainAssistant.prototype.handleReorder = function(event) {
  Mojo.Log.info("reorder event %j", event.item, event.toIndex, event.fromIndex);

  var temp=''; 
 
  this.myListModel.items.splice(event.fromIndex, 1);
  this.myListModel.items.splice(event.toIndex, 0, event.item);
  
  for (var j=0;j < this.myListModel.items.length;j++) {
    temp = temp + this.myListModel.items[j].id + '|';
  }
  
  var newtutsdata = '|' + temp;
  
  var myCookie = new Mojo.Model.Cookie('TutsPlusCookie');
  myCookie.put({ tutsdata: newtutsdata });
  
}

The handleDelete function does almost the same, it first removes the deleted item from the lists model and then again constructs a new cookie value out of the model and saves that.

MainAssistant.prototype.handleDelete = function(event) {
  Mojo.Log.info("delete event "+event.item);
  this.myListModel.items.splice(this.myListModel.items.indexOf(event.item), 1);
   
  var temp=''; 
   
  for (var j=0;j < this.myListModel.items.length;j++) {
    temp = temp + this.myListModel.items[j].id + '|';
  }
  var newtutsdata = '|' + temp;
 
  var myCookie = new Mojo.Model.Cookie('TutsPlusCookie');
  myCookie.put({ tutsdata: newtutsdata });
  
}

Now you can go ahead and reorder the list in the main scene and even delete items you don't want to see. Just hold and drag an item to reorder it. To delete an item, you slide with your finger over it and it will ask you if you want to delete it from the list.

Wrap up

We've covered quite a range of new topics to expand the tutsplus app. We learned how to use the WebView widget to display website contents, and then how to handle list item reordering and deleting. Hopefully you've enjoyed reading and learned a lot!

Advertisement