Tuesday, June 28, 2011

PEPBrowser: The First Evently Widget

Introduction

In this blog post, I will be walking you through on how I wrote the first Evently widget for the PEPBrowser App. The widget simply displays a listing of the main categories of the PEP documents. For those who would like to get the documents used for this project, simply replicate it from this CouchDB database, http://nieldomingo.iriscouch.com/pepbrowser/_design/pepbrowser/.

The PEP Document Represented in CouchDB

First and foremost, we have to understand the structure of the PEP doument stored in Couchdb. Below is an example of the PEP document as stored in Couchdb.


{
   "_id": "00808d5fefdabc7c068ed3089d08aac3",
   "_rev": "1-f4e2d53f17d1b8ff0842baf921f773b2",
   "category": "Process",
   "status": "Active",
   "num": "1",
   "version": "b5ab214ac135",
   "created": "13-Jun-2000",
   "url": "http://www.python.org/dev/peps/pep-0001",
   "lastmodified": "2011-03-04 05:03:26 +0000 (Fri, 04 Mar 2011)",
   "author": "Barry Warsaw, Jeremy Hylton, David Goodger",
   "html": "<div class=\"contents ...",
   "title": "PEP Purpose and Guidelines",
   "type": "pep"
}

The definition of the fields that we would be using follows.
  • type - the document type. I used the value, 'pep', to identify the PEP document.
  • category - the category of the PEP document.
  • status - the status of the PEP document. It determines whether the PEP is accepted, rejected, active, etc.
  • num - the number of the PEP document. PEP documents are numbered; they are usually referred as PEP 1, PEP 3000, etc.
  • title - the title of the PEP.
  • html - the html of the PEP document body.
The categories View

Before proceeding to writing the first Evently widget, we first need to make a CouchDB view that will generate a query of the information to be displayed by the widget. The widget would show a listing of all the PEP document categories and the number of documents for each category.

To start making this view, let us first generate some boiler-plate code using the couchapp utilty by running the following command.

couchapp generate view categories

The above command would generate a folder, named 'categories', inside the 'views' folder. Inside the 'categories' folder are two files, map.js and reduce.js. The map.js would contain the code for mapping part of the view and reduce.js would contain the code for the reduction part of the view.

The code for map.js follows.


function(doc) {
  if (doc.type == 'pep') {
    emit(doc.category, 1);
  }
}

The code for reduce.js follows.

function(keys, values, rereduce) {
  return sum(values);
}

The above view when run with a group_level=1 parameter, http://localhost:5984/pepbrowser/_design/pepbrowser/_view/categories?group_level=1, produces the following output.

{"rows":[
{"key":"Informational","value":38},
{"key":"Process","value":22},
{"key":"Standards Track","value":218}
]}


Categories List Evently Widget

Now that we have a CouchDB view, let us proceed with creating the evently widget. In the 'evently' folder of our Couchapp, create the folder, 'peplist'. 'peplist' would be the name of our widget. Inside the 'peplist' folder, create the folder '_init'. '_init' is the event that is triggered when the widget is loaded. This widget is intended to be part of the start page of the app so most of the work is done during initialization. Thus all our following activities in creating this widget is done inside the '_init' folder.

Inside the '_init' folder, create the query.json file. It should contain the following JSON.

{
  "view": "categories",
  "group_level": 1
}

The query.json file indicates the query to be done by the '_init' event. The 'view' field indicates the CouchDB view to be used and 'group_level' is a parameter to be used in making the query. The result of this query is passed to the function inside the 'data.js' function for processing.

Also under the '_init' folder, create the 'data.js' file with the following content.


function (data) {
return {'categories': data.rows};
};

The 'data' argument in the above function contains the result of the 'categories' view as defined by query.json. The above function is a simple function that returns a mapping to be used by the mustache template.

Create the mustache template inside the _init' folder. The filename of the mustache template should be 'mustache.html'. And for this case, it should contain the following markup.

<ul id="peplist" data-role="listview" data-theme="c" data-dividertheme="b">
  {{#categories}}
  <li><a href="#categorystatuslist" title="{{ key }}">{{key}} ({{value}})</a></li>
  {{/categories}}
</ul>

Notice in the above template that it lists down each and every row of the 'categories' field passed by the mapping of 'data.js'. Each row is represented by a list item tag, 'li', and a link tag, 'a'. The text contained in the link is the category name and the number of documents, i.e. "Informational (38)". The values of the 'href' and 'title' attributes contains values that will be explained later when we linked this widget to other widgets.

Lastly, we need to create the 'after.js' file with the following contents.

function () {
$('#peplist').listview();
};

The 'after.js' contains code that would be run  by the widget after all the other functions have been run, which explains its name. The function is necessary in order to initialize the list into a Jquerymobile list.

After all our changes, the peplist widget folder should look as follows.


Using the Evently Widget

To use the widget inside the main page of the app, we need to modify the 'main.html' file in the '_attachments' folder as follows.

<!doctype html>
<head>
  <title>PEP Browser</title>
  <link rel="stylesheet" href="style/jquery.mobile-1.0a4.1.min.css" type="text/css">
  <script src="js/myloader.js"></script>
  <script src="js/jquery.mobile-1.0a4.1.min.js"></script>
  <script type="text/javascript" charset="utf-8">
    $.couch.app(function(app) {
      $("#maincategorylist").evently("peplist", app);    
    });
  </script>
</head>
<body>
  <div data-role="page" id="categorylist">
    <div  data-role="header" data-theme="b">
      <h1>PEP Browser</h1>
    </div> 
<div  data-role="content">
 <div id="maincategorylist">
 </div>
</div> 
  </div>
</body>
</html>

The highlighted Javascript above connects the Evently widget we just created to the 'maincategorylist' div.

$("#maincategorylist").evently("peplist", app);

This means that the 'maincategorylist' div would contain the widget. It would display the markup generated by the widget.


After all of these changes, the app would look as follows.




No comments:

Post a Comment