Sunday, November 6, 2011

Learning Ramaze (4) - Updating Body Contents

I am learning Ramaze, a small Ruby web framework. I am building an application that will be used for PostgreSQL database management.

My application has four main pages: Home, Data, Design and System. I have finished learning how to navigate between these pages. Now I would like to learn how to update body section of contents of each pages. I do not want to load a whole page when changes are limited to the body section of the page.

In this post, I would like to modify my Home page, which is the simplest of all. The Home page basically explains what this application does (PostgreSQL database management), and what features it has (Data, Design, System). It can be static as is now, but I would like to add some interactive elements. I would like to add a link (or button) for each section so that when it is clicked, it will expand the description, showing more information in detail. When it is clicked again, it will shrink to display a short, original description.

1. Resource(s)
Ramaze: http://www.ramaze.net/
AJAX Tutorial: http://www.w3schools.com/ajax/default.asp
My first post: Learning Ramaze (1)
My second post: Learning Ramaze (2)
My third post: Learning Ramaze (3)

2. How to Update Contents without Loading Whole Page
An event such as mouse click triggers a process of content updates. Browser builds a request message and sends it to the server. The server processes the request and builds a response message, optionally accessing database or file system. Then it sends the response message back to the browser. The browser process the response and updates the content accordingly.






























3. Identifying Target (Part(s) of Contents) to Update

In my Home page, it is the "Features" section where I want to update its contents upon an event of user request. For example, when user clicks on "Design" item of the feature list, I want to display a longer description of that feature. So I enclose each item with
<div id="..."></div>tag and provide with unique IDs.
...
<ul>
  <li>
    <div id="design">Create and Design Databases.</div>
  </li>
  <li>
    <div id="data">View/Add/Edit/Delete Database Records.</div>
  </li>
  <li>
    <div id="report">Generate Reports.</div>
  </li>
  <li>
    <div id="system">Configure System.</div>
  </li>
</ul>


4. Planting an Event Handler that Triggers a Chain of Actions

An event such as mouse click starts a chain of actions that in the end update the specified part(s) of page contents. A javascript is used to handle this event and send its request to the server. In my Home page, I append "(read more...)" as an anchor at the end of each list item, and when it is clicked, it calls a javascript function "requestMore()".

So the above html code becomes:
...
<ul>
  <li>
    <div id="design">Create and Design Databases. (<a href="javascript: requestMore('design')">more...</a>)</div>
  </li>
  <li>
    <div id="data">View/Add/Edit/Delete Database Records. (<a href="javascript: requestMore('data')">more...</a>)</div>
  </li>
  <li>
    <div id="report">Generate Reports. (<a href="javascript: requestMore('report')">more...</a>)</div>
  </li>
  <li>
    <div id="system">Configure System. (<a href="javascript: requestMore('system')">more...</a>)</div>
  </li>
</ul>
It displays like this:










5. Loading Javascript file(s)

I'd like all my javascripts in external file(s). Ramaze provides a simple way to load javascrpt file. For example, I can use js method to load a file that resides at /public/js/ directory like this:
<!-- layout/default.xhtml -->
<!DOCTYPE html>
<html lang="en">
    <head>
       ...
       #{js('myscripts')}      <!-- public/js/myscripts.js -->
    </head>
    ...
But Ramaze layout such as this "default.xml" is called for all pages, and I do not want to load scripts that are not related to particular page that is being displayed. So I use another instance variable (@javascript) that is dynamically updated in order to load different file for different page.
<!-- layout/default.xhtml -->
<!DOCTYPE html>
<html lang="en">
    <head>
       ...
       #{@javascript}
    </head>
    ...
I create one javascript file for each page (controller); for example, home.js file for Home page, data.js file for Data page, and so on.
'


























Each controller updates @javascript variable for each page.
# controller/main.rb
#
class MainController < Controller
  map '/'
  def index
    @subtitle = 'Home'
    @menu = build_menu 'Home'
    @javascript = load_javascript 'Home'
  end
end

class DataController < Controller
  map '/data'
  def index
    @subtitle = 'Data'
    @menu = build_menu 'Data'
    @javascript = load_javascript 'Data' 
  end
end
...

And here is the definition of the load_javascript() method.
class Controller < Ramaze::Controller
  ...
  def load_javascript(current_menu)
    file = current_menu.downcase + ".js"     # main.js, data.js, design.js, system.js
    return ""
  end
end
A resulted html, for example, should look like:




6. Writing Javascript codes that Respond to Event (Simple Test)
Now I can load any javascript file. It is time to write a script that actually responds to an event - a mouse click. First, I write simle codes to test if mouse click gets a response.
/* public/js/home.js */

function requestMore(id)
{
  document.getElementById(id).innerHTML = "Testing " + id + " (less ...)"
}

function requestLess(id)
{
  document.getElementById(id).innerHTML = "Testing " + id + " (more ...)"
}

When "more..." anchor is clicked, it displays the following. It works.

















7. Writing Javascript codes that Respond to Event (AJAX)

A simple test worked. But the content was manually created and not from the server. Now I need to get actual content that comes from the server. To do that, I need to use AJAX. Basically, I create a request object packed with necessary information for obtaining appropriate content and updating part of page. Then I send it to the server which in turn sends back a response object which knows how to update the target area in the page.

This is modified version of home.js.
/* public/js/home.js */

function requestMore(id)
{
 var filename = id + "_more.xhtml"  // design_more.xhtml, data_more.xhtml, etc. 
 
 var request = new XMLHttpRequest();
 request.onreadystatechange=function(){
  if(request.readyState==4 && request.status==200){
   document.getElementById(id).innerHTML = request.responseText;
  }
 }
 request.open("GET", filename,true);
 request.send();
}

function requestLess(id)
{
 var filename = id + "_less.xhtml"  // design_less, data_design, etc
 
 var request = new XMLHttpRequest();
 request.onreadystatechange=function(){
  if(request.readyState==4 && request.status==200){
   document.getElementById(id).innerHTML = request.responseText;
  }
 }
 request.open("GET", filename,true);
 request.send();
}
It retrieves contents of files that reside on server. For example, To display expanded description about Design page, it retrieves design_more.xhtml. To retrieve shorter descrition (default) about Design page, it retrieves design_less.xhtml. And so on.
<!-- public/design_more.xhtml -->
 Create and Design Databases. (<a href="javascript: requestLess('design')">less ...</a>) <br />
 You can create/modify/delete databases. <br />
 You can save/retrieve documents related to database designs.<br />
<!-- public/design_less.xhtml -->
 Create and Design Databases. (<a href="javascript: requestMore('design')">more ...</a>) <br />
Clicking "more..." and "less..." will display the following page as shown back and force.

Saturday, November 5, 2011

Installing git on Ubuntu (11.04)

Installed git.

1 Resorce(s)
http://help.github.com/linux-set-up-git/

2. Installation
Use Synaptic to search and install 'git'

3. Test
$ git --version
git version 1.7.4.1
$ 

4. Start Tracking my App with Git
$ cd ~/public_html/apps/dbmanager
$ git init
Initialized empty Git repository in /home/socrateos/public_html/apps/dbmanager/.git/
$ git add .
$ git commit -m "new app"

Installing Rhino (Javascript shell) on Ubuntu (11.04)

I installed Rhino (Javascript Shell) so that I can test some javascripts interactively just like irb for Ruby.

1. Resource(s)
Mozilla Rhino Project: http://www.mozilla.org/rhino/
Rhino Debugger: http://manpages.ubuntu.com/manpages/natty/man1/rhino-debugger.1.html

2. Installation
Search and install "Rhino" from Ubuntu Software Center.

3. Test
$ js
Rhino 1.7 release 2 2010 11 17
js> "hello".length
5
js> quit()
$