Advertisement

Build a Cross-Platform Twitter Client: Completing the Code Review

by

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

In this series, we will develop a Twitter client using the jQuery Mobile and PhoneGap frameworks. This project will be deployed to Android and iOS environments as a native application. The user interface of the application, called simply "Tweets", will be built using jQuery Mobile and PhoneGap will be used to create the native application. We will also use the PhoneGap Storage API to access native database functionality. All coding will be done with HTML and JavaScript utilizing jQuery, jQuery Mobile, and the PhoneGap libraries.


Also available in this series:

  1. Build a Cross-Platform Twitter Client: Overview
  2. Build a Cross-Platform Twitter Client: Twitter API & Code Review
  3. Build a Cross-Platform Twitter Client: Completing the Code Review
  4. Build a Cross-Platform Twitter Client: Deployment

Organization Of Part III Of This Series

In Part II, we started reviewing the Tweets application. In "Review Of index.html", our main focus was on the static structure of the HTML and jQuery Mobile code that make up the application screens. The section named "Twitter API" gave an overview of the Twitter API methods user_timeline and search. The next section, "Code Review", gave a review of the JavaScript code that implements the application functionality. Part II discussed "Initial Page Load", "Utility Functions", "Database Access Functions", and started the discussion on "Core Business Logic Functions".

In Part III, we will continue inspecting the "Core Business Logic Functions" taking up from where we left in Part II and finish the code review of the Tweets application by looking at "Event Handlers" & "Page Display Functions".


Code Review - Core Business Logic Functions (Continued)

Function storeCurrentInput()

storeCurrentInput() is responsible for iterating through the current list view of search terms & screen names, constructing a comma separated string consisting of those entries and passing those entries to putInputsIntoStorage() as a parameter. The function putInputsIntoStorage() then utilizes the PhoneGap database API to store those entries in the local database. The following are the constants used in this function.

 
var EMPTY = ''; 
var LI = 'li'; 
var ID = 'id'; 
var COMMA = ','; 
var PREFIX = '^';

The following is a full listing of the function.

 
function storeCurrentInput(){				 
  var tmp = EMPTY; 
  currentInputsVar.find(LI).each(function(){	 
    var plainId = $(this).attr(ID); 
    if(plainId.match(/_d_li_s$/)){ 
      tmp = tmp + COMMA + PREFIX +$(this).attr(ID).substring(5,$(this).attr(ID).length-7); 
    }else{ 
      tmp = tmp + COMMA + $(this).attr(ID).substring(5,$(this).attr(ID).length-5); 
    }					 
  }); 
  if(tmp.length < 1){ 
    putInputsIntoStorage(tmp); 
  }else{ 
    putInputsIntoStorage(tmp.substring(1)); 
  }				 
}

The variable tmp will store the comma separated list of screen names & search terms. Initially it is an empty string. Note that the global variable currentInputsVar points to either the list view with id='currentInputs' (narrow-screen device) or id='currentInputsCell' (wide-screen device). Using jQuery find() and each() functions, we iterate through the list. The plainId variable is set to the value of the id attribute of the current list item. From review of addInput(), the id attribute always starts with nput_. If a search term, the id attribute ends with _d_li_s, e.g. id='nput_fortlauderdale_d_li_s'. If a screen name, it ends with _d_li, e.g. id='nput_SunSentinel_d_li'.

If the value is a search term, we remove the first 5 characters, nput_, and the last 7 characters, _d_li_s, from value of the id attribute, add the prefix ^ and append the resulting string to tmp variable following a ','. For example, if id='nput_fortlauderdale_d_li_s' then we append ,^fortlauderdale to tmp. Similarly, if it is a screen name, we remove the first 5 characters, nput_, and the last 5 characters, _d_li, from the value of the id attribute and append the resulting string to the tmp variable following a ','. For example, if id='nput_SunSentinel_d_li', then we append ,SunSentinel to tmp.

 
function storeCurrentInput(){				 
  var tmp = EMPTY; 
  currentInputsVar.find(LI).each(function(){	 
    var plainId = $(this).attr(ID); 
    if(plainId.match(/_d_li_s$/)){ 
      tmp = tmp + COMMA + PREFIX +$(this).attr(ID).substring(5,$(this).attr(ID).length-7); 
    }else{ 
      tmp = tmp + COMMA + $(this).attr(ID).substring(5,$(this).attr(ID).length-5); 
    }					 
  }); 
  ...

After the iterations are completed, we now have a string variable tmp to be passed to putInputsIntoStorage(). If tmp is an empty string, that is the list of search terms & screen names is empty, then we pass putInputsIntoStorage() into an empty string (this is still needed, because putInputsIntoStorage() will clear the local database when called with an empty string). If the value is not an empty string, the first character in tmp is a ',' and hence we remove it before passing the value of tmp to putInputsIntoStorage().

 
  ... 
  if(tmp.length < 1){ 
    putInputsIntoStorage(tmp); 
  }else{ 
    putInputsIntoStorage(tmp.substring(1)); 
  }				 
}

Function getTweets()

The getTweets() function performs an ajax() call to the Twitter API to get tweets in a user's timeline. There are two parameters passed to the function: the screen name of the user whose timeline will be requested and a function name to handle the response from the ajax() call. The code listing for the function is given below.

 
function getTweets(varUsr,handler){				 
  var params = {screen_name:varUsr}; 
  requestObject = $.ajax({dataType: XML, url: TWEETS_URI, data: params, success: handler}); 
  return false;  
}

The first step is to construct an array where the screen name is passed as a value of a parameter named screen_name. Then, using the jQuery ajax() function, we make a call to the Twitter API. The TWEETS_URI is a constant which is defined as:

 
  TWEETS_URI='http://api.twitter.com/1/statuses/user_timeline.xml'

For example, if the varUsr parameter has the value SunSentinel, then a get request corresponding to the ajax() call above becomes:

 
  http://api.twitter.com/1/statuses/user_timeline.xml?screen_name=SunSentinel

The function returns after making the ajax() call. The result from the ajax() call, which is asynchronous by nature, will be handled by the handler function passed as a value of the parameter handler. The global requestObject variable is set to the jQuery XMLHttpRequest object returned from the ajax() call. The requestObject variable will be used, if needed, to abort the ajax() call (see the review of buttonProgShowInputsVar.click()).

Function getSearch()

The getSearch() function is similar to getTweets(). It performs an ajax() call to the Twitter Search API to get tweets by any user where the tweet content matches a search query. There are two parameters passed to the function: a search term and a function name to handle the response from the ajax() call. The code listing for the function is given below:

 
function getSearch(searchTerm,handler){							 
  var params = {q:searchTerm}; 
  requestObject = $.ajax({dataType: TEXT, url: SEARCH_URI, data: params, success: handler}); 
  return false; 
}

The first step is to construct an array where the search term is passed as value of a parameter named q. Then, using the JQuery ajax() function, we make a call to the Twitter Search API. The SEARCH_URI is a constant defined as:

 
SEARCH_URI='http://search.twitter.com/search.json'

For example, if the searchTerm parameter has the value fortlauderdale, then a get request corresponding to the ajax() call above becomes:

 
http://search.twitter.com/search.json?q=fortlauderdale

The function returns after making the ajax() call. The results from the ajax() call, which is asynchronous by nature, will be handled by the handler function passed as a value of the parameter handler.

Function populateTweetItems()

populateTweetItems() is responsible for parsing the XML sent by the Twitter API in response to the user_timeline request, extracting message content from the response and finally creating an HTML table to display that content. The XML text is an input parameter to the function.

An example of XML text sent by the Twitter API in response to a user_timeline request is given below, where we show only the content relevant to our application:

 
<?xml version="1.0" encoding="UTF-8"?> 
<statuses type="array"> 
  <status> 
    <created_at>Sat Oct 08 18:44:37 +0000 2011</created_at> 
    ... 
    <text>Check out a photo gallery of South Floridians braving the storm Saturday: http://t.co/a5rEUND5</text> 
    ... 
  </status> 
  <status> 
    <created_at>Sat Oct 08 12:30:29 +0000 2011</created_at> 
    ... 
    <text>Wind, rain could pose threats Saturday in South Florida: http://t.co/YMt8AQyW</text> 
    ... 
  </status> 
  ... 
</statuses>

The XML shown above is a response to http://api.twitter.com/1/statuses/user_timeline.xml?screen_name=SunSentinel where SunSentinel is a screen name of the South Florida newspaper the Sun Sentinel. Like many other media organizations, the Sun Sentinel frequently tweets latest news in Twitter. With each news item, it provides a URL link with further detail on the news on their web site.

Constants used in the function are given below:

 
var EMPTY = ''; 
var STATUS = 'status'; 
var WHEN = 'created_at'; 
var SPACE = ' '; 
var TEXT = 'text'; 
var HTML_FRG7 = '<tr><td>'; 
var HTML_FRG8 = '<hr></hr></td></tr>'; 
var EM1 = '<em>'; 
var EM2 = '</em> '; 
var MAX_TWEETS = 11; 
var TABLE_OPEN = '<table STYLE="border-spacing: 10pt 0pt">'; 
var TABLE_CLOSE = '</table>';

The complete code listing for populateTweetItems() is given below.

 
function populateTweetItems(xml){ 
  var tmpTxt = EMPTY; 
  var indx = 0; 
  $(xml).find(STATUS).each(function(){ 
    var when = $(this).find(WHEN).first().text().split(SPACE,4).join(SPACE);						 
    var txt = $(this).find(TEXT).text();					 
    tmpTxt = tmpTxt + HTML_FRG7 + EM1 + when + EM2 + addHref(txt) + HTML_FRG8;   
    if(++indx >= MAX_TWEETS){ 
      return false; 
    } 
  }); 
 
  resultsVar.html(TABLE_OPEN + tmpTxt + TABLE_CLOSE); 
  showResults(); 
}

The function populateTweetItems() starts with defining two variables, tmpTxt and indx. Parsing the XML text is done using the jQuery API. The code fragment $(xml).find(STATUS).each() extracts each instance of the <status> element from the XML. An inner function is passed to the each() function to further process the <status> element.

 
  ... 
  $(xml).find(STATUS).each(function(){ 
    var when = $(this).find(WHEN).first().text().split(SPACE,4).join(SPACE);						 
    var txt = $(this).find(TEXT).text();					 
    tmpTxt = tmpTxt + HTML_FRG7 + EM1 + when + EM2 + addHref(txt) + HTML_FRG8;   
    if(++indx >= MAX_TWEETS){ 
      return false; 
    } 
  }); 
  ... 
}

The expression $(this).find(WHEN).first().text().split(SPACE,4).join(SPACE) extracts the <created_at> element from <status>, parses the first four tokens, and then sets the variable named when to a string consisting of those tokens. The format of <created_at> is as follows:

  • First token: day of week (e.g. Sat)
  • Second token: month of year (e.g. Oct)
  • Third token: day of month (e.g. 08)
  • Fourth token: HH24:MM:SS (e.g. 18:44:37, the time in 24-hour format)
  • Fifth token: local differential hours from GMT (e.g. +0000)
  • Sixth: year (e.g. 2011)

For example, if the value of <created_at> is Sat Oct 08 18:44:37 +0000 2011, then the value of the variable becomes Sat Oct 08 18:44:37. For the sake of simplicity, we ignore the year and differential from GMT time zone in this tutorial series.

The expression $(this).find(TEXT).text() extracts the value of the <text> element. This is the text content of the status (tweet). A variable named txt is set to the value of the <text> element. Then, we construct an HTML table row using when and txt variables. The utility function addHref() processes the text passed to it and puts any URL starting with http:// inside an <a> tag. As an example, consider the following fragment:

 
  <created_at>Sat Oct 08 18:44:37 +0000 2011</created_at> 
    ... 
  <text>Check out a photo gallery of South Floridians braving the storm Saturday: http://t.co/a5rEUND5</text>

The expression below:

 
  HTML_FRG7 + EM1 + when + EM2 + addHref(txt) + HTML_FRG8;

becomes:

 
  <tr><td><em>Sat Oct 08 18:44:37</em>  
    Check out a photo gallery of South Floridians braving the storm Saturday:  
    <a href='http://t.co/a5rEUND5'>http://t.co/a5rEUND5</a><hr></hr></td></tr>

The above is broken into multiple lines for readability, the original expression is a single line.

It then gets appended to the current value of tmpTxt.

The expression below limits the processing of <status> elements (tweets) to the value of the constant MAX_TWEETS, which is defined as 11.

 
if(++indx >= MAX_TWEETS){ 
  return false; 
}

The last 2 lines of populateTweetItems() are as follows:

 
  ... 
  resultsVar.html(TABLE_OPEN + tmpTxt + TABLE_CLOSE); 
  showResults();

For narrow-screen devices, resultsVar is a variable pointing to the <div> element with id='contentResults'. For wide-screen devices, resultsVar is a variable pointing to the <div>element with id='resultsCell'. We define a table and set the previously constructed rows as its content. Then, we place the table in the <div> element referenced by resultsVar. Finally, we call the showResults() function to display the Results page (for wide-screen devices, the showResults() function will have no effect).

Function populateSearchItems()

The populateSearchItems() function is very similar to the populateTweetItems(). It parses the JSON formatted text sent by the Twitter API in response to a search request, extracts message content from it, and finally creates an HTML table to display that content. The structure of the JSON text is in the following format where we consider only the elements that are relevant to this application.

 
{... 
  "results":[{"created_at":"...",...,"text":"..."}, 
             {"created_at":"...",...,"text":"..."},...] 
  ... 
}

The results array consists of search results. Each entry of the array starts with an element named created_at whose value is a date/time stamp. An example is as follows:

 
"created_at":"Sun, 09 Oct 2011 20:06:49 +0000"

The text element in each entry of the results array contains the text message (tweet) that is related to the search term. Note that the search term may be part of the value of the text element or some other element in the results array. An example of the text element that is returned in response to the search term

fortlauderdale

is given below:

 
"text":"Turtle-friendly lighting at McSorleys (video) http://t.co/GqrLOlGn  #Irish #Beach #Pub #FortLauderdale"

The following is a list of constants used by the function:

 
var EMPTY = ''; 
var SPACE = ' '; 
var HTML_FRG7 = '<tr><td>'; 
var HTML_FRG8 = '<hr></hr></td></tr>'; 
var EM1 = '<em>'; 
var EM2 = '</em> '; 
var MAX_TWEETS = 11; 
var TABLE_OPEN = '<table STYLE="border-spacing: 10pt 0pt">'; 
var TABLE_CLOSE = '</table>';

A complete listing for the function is given below:

 
function populateSearchItems(jsonText){				 
  var tmpTxt = EMPTY; 
  var indx = 0; 
  var result = $.parseJSON(jsonText);   
  if(result != null){ 
    var resultsArr =  result.results;  
    if(resultsArr != null){ 
      for(var i = 0; i < resultsArr.length; i++){ 
        var txt = resultsArr[i].text; 
        var whenArr = (resultsArr[i].created_at).split(SPACE,5); 
        var when = whenArr[0] + SPACE + whenArr[1] + SPACE + whenArr[2] + SPACE + whenArr[4]; 
        tmpTxt = tmpTxt + HTML_FRG7 + EM1 + when + EM2 + addHref(txt) + HTML_FRG8;   
        if(++indx >= MAX_TWEETS){ 
          break; 
        } 
      } 
    } 
    resultsVar.html(TABLE_OPEN + tmpTxt + TABLE_CLOSE); 
    showResults();					 
  } 
  return false;				 
}

The function starts by declaring local variables tmpTxt and indx. Then, we use the jQuery parseJSON() function call passing the JSON formatted text as an argument. The parsed JavaScript object is referenced via a variable named result. If result is not null, it should contain an array named results. A variable named resultsArr holds a reference to that array. If the array is not null, we iterate through it and extract the text and created_at elements from it, as shown below:

 
    ... 
    if(resultsArr != null){ 
      for(var i = 0; i < resultsArr.length; i++){ 
        var txt = resultsArr[i].text; 
        var whenArr = (resultsArr[i].created_at).split(SPACE,5); 
        ...

The created_at element consists of 6 tokens (see the example above):

  • First token: Day of the week followed by a comma, e.g. Sun,
  • Second token: Day of the month, e.g. 09
  • Third token: Month of the year, e.g. Oct
  • Fourth token: Year, e.g. 2011
  • Fifth token: HH24:MM:SS, e.g. 20:06:49, time in 24-hour format
  • Sixth token: local differential hours from GMT

Since we are interested up to the first five tokens, we use the JavaScript split() function to extract those and put them into an array named whenArr.

The code continues as follows:

 
  ... 
      var when = whenArr[0] + SPACE + whenArr[1] + SPACE + whenArr[2] + SPACE + whenArr[4]; 
      tmpTxt = tmpTxt + HTML_FRG7 + EM1 + when + EM2 + addHref(txt) + HTML_FRG8;   
      if(++indx >= MAX_TWEETS){ 
        break; 
      } 
    }     
  } 
  ...

Above, we create a text variable named when that consists of the first, second, third, and fifth tokens, separated by a space (e.g. Sun, 09 Oct 20:06:49). Then, we construct an HTML formatted string and append it to the tmpTxt variable. For each entry in the results array, the HTML formatted string represents a table row consisting of when and txt variables, where any URL inside the txt variable is surrounded by an <a> tag. This is the same technique we used in populateTweetItems() above. For example:

   
"created_at":"Sun, 09 Oct 2011 20:06:49 +0000"  
"text":"Turtle-friendly lighting at McSorleys (video) http://t.co/GqrLOlGn  #Irish #Beach #Pub #FortLauderdale"

This will yield:

 
<tr><td><em>Sun, 09 Oct 20:06:49</em> Turtle-friendly lighting at McSorleys (video)  
  <a href="http://t.co/GqrLOlGn">http://t.co/GqrLOlGn</a>   
  #Irish #Beach #Pub #FortLauderdale<hr></hr></td></tr>

Finally, we put a limit on the number of entries of the

results

array processed. Where are, at most, MAX_TWEETS entries are allowed.

The resulting HTML formatted string, represented by the variable tmpTxt, consists of a unique table row for each search result. The last several lines of the code listing is as follows. Here, we place those table rows inside a <table> tag. This is set as the content of the <div> element referenced by resultsVar. Finally, we call the showResults() function to show the Results page (for wide-screen devices, calling the showResults() function will have no effect).

 
    ... 
    resultsVar.html(TABLE_OPEN + tmpTxt + TABLE_CLOSE); 
    showResults();						 
  } 
  return false;				 
}

Event Handlers

In this section, we will review the functions that handle user events.

Function buttonAddUserClicked()

The function buttonAddUserClicked() is the event handler when the user presses on the button to add a screen name.

 
var EMPTY = ''; 
var UL = 'ul'; 
var REFRESH = 'refresh'; 
... 
function buttonAddUserClicked(){ 
  var tmpInput = $.trim(txtInputVar.val()); 
  if(tmpInput.length < 1){ 
    return false; 
  }				 
  addInput(txtInputVar.val(),false); 
  txtInputVar.val(EMPTY); 
  $(UL).listview(REFRESH); 
  storeCurrentInput();				 
}

The global variable txtInputVar points the text field with id='txtInput' (narrow-screen device) or id='txtInputWide' (wide-screen device). The value of txtInputVar is trimmed and, if different than an empty string, it is passed to addInput to add to the list view of screen names & search terms. The second parameter to addInput is the Boolean false to indicate that this is a screen name not a search term. Then, the text field referenced by txtInputVar is cleared, the list view of search terms and screen names is refreshed via the jQuery Mobile listview('refresh') and the storeCurrentInput() function is called to store the entries of the list view in the local database.

Function buttonAddSearchClicked()

The function buttonAddSearchClicked() is similar to buttonAddUserClicked(). It is the event handler when the user presses on the button to a search term. The code listing is given below.

 
var EMPTY = ''; 
var UL = 'ul'; 
var REFRESH = 'refresh'; 
... 
function buttonAddSearchClicked(){ 
  var tmpInput = $.trim(txtInputVar.val()); 
  if(tmpInput.length < 1){ 
    return false; 
  }				 
  addInput(txtInputVar.val(),true); 
  txtInputVar.val(EMPTY); 
  $(UL).listview(REFRESH); 
  storeCurrentInput();				 
}

The global variable txtInputVar points the text field with id='txtInput' (narrow-screen device) or id='txtInputWide' (wide-screen device). The value of txtInputVar is trimmed, and, if different than an empty string, it is passed to addInput to add to the list view of screen names & search terms. The second parameter to addInput is the Boolean true to indicate that this is a search term. Next, the text field referenced by txtInputVar is cleared, the list view of screen names & search terms is refreshed via the jQuery Mobile function listview('refresh') and the storeCurrentInput() function is called to store the entries of the list view in the local database.

Inline Event Handlers

In this section, we will review various event handlers that are defined inline.

The global variable buttonHdrShowInputsVar represents the back button in header of the Results page. When that button is clicked, the showInputs() function is called to display the Inputs page.

 
buttonHdrShowInputsVar.click(function() { 
  showInputs(); 
  return false;       
});

Similarly, the global variable buttonFtrShowInputsVar represents the back button in the footer of the Results page. When that button is clicked, the showInputs() function is called to display the Inputs page.

 
buttonFtrShowInputsVar.click(function() { 
  showInputs(); 
  return false;       
});

The global variable buttonProgShowInputsVar represents the back button in the Progress page. From a review of the getSearch() and getTweets() functions, the global variable requestObject is set to the jQuery XMLHttpRequest object returned from the ajax() calls to the Twitter API. When that button is clicked, the jQuery abort() function is called on the XMLHttpRequest object to end the ajax() call. Then, the Inputs page is displayed.

 
buttonProgShowInputsVar.click(function() { 
  try{ 
    requestObject.abort(); 
  }catch(err){} 
  showInputs(); 
  return false;       
  });

The global variable buttonAddUserVar represents the button with 'Add Screen Name' label in the Inputs page. When that button is clicked, the buttonAddUserClicked() function is called.

 
buttonAddUserVar.click(function() { 
  buttonAddUserClicked(); 
  return false; 
});

The global variable buttonAddSearchVar represents the button with 'Add Search Term' label in Inputs page. When that button is clicked, the buttonAddSearchClicked() function is called.

 
buttonAddSearchVar.click(function() { 
  buttonAddSearchClicked(); 
  return false; 
});

The global variable buttonAddUserWideVar represents the button with the 'Add Screen Name' label in the Wide Content page. When that button is clicked, the buttonAddUserClicked() function is called.

 
buttonAddUserWideVar.click(function() {				 
  buttonAddUserClicked(); 
  return false; 
});

The global variable buttonAddSearchWideVar represents the button with the "Add Search Term" label in Wide Content page. When that button is clicked, the buttonAddSearchClicked() function is called.

 
buttonAddSearchWideVar.click(function() { 
  buttonAddSearchClicked(); 
  return false; 
});

Page Display Functions

In this section, we will review functions that control hiding/displaying pages. Those functions are key to controlling the screen flow.

Function hideInputs()

The function hideInputs hides the header, content, and footer sections of the Inputs page. Note that hdrInputsVar, contentInputsVar, and ftrInputsVar are constants pointing to the <div> elements for the header, content, and footer sections of the Inputs page, respectively.

 
var hdrInputsVar = $('#hdrInputs'); 
var contentInputsVar = $('#contentInputs'); 
var ftrInputsVar = $('#ftrInputs'); 
... 
function hideInputs(){ 
  hdrInputsVar.hide(); 
  contentInputsVar.hide(); 
  ftrInputsVar.hide(); 
}

Function hideResults()

This function hides the header, content and footer sections of the Results page. Note that hdrResultsVar, contentResultsVar, and ftrResultsVar are constants pointing to the <div> elements for the header, content, and footer sections of the Results page, respectively.

 
var hdrResultsVar = $('#hdrResults'); 
var contentResultsVar = $('#contentResults'); 
var ftrResultsVar = $('#ftrResults'); 
... 
function hideResults(){ 
  hdrResultsVar.hide(); 
  contentResultsVar.hide(); 
  ftrResultsVar.hide(); 
}

Function hideProgress()

This function hides the header, content and footer sections of the Progress page. Note that hdrProgressVar, contentProgressVar and ftrProgressVar are constants pointing to the <div> elements for the header, content and footer sections of the Progress page, respectively.

 
var hdrProgressVar = $('#hdrProgress'); 
var contentProgressVar = $('#contentProgress'); 
var ftrProgressVar = $('#ftrProgress'); 
... 
function hideProgress(){ 
  hdrProgressVar.hide(); 
  contentProgressVar.hide(); 
  ftrProgressVar.hide(); 
}

Function showInputs()

This function shows the header, content, and footer sections of the Inputs page and hides the Progress, Results, and the Wide pages. Note that hdrInputsVar, contentInputsVar and ftrInputsVar are constants pointing to the <div> elements for the header, content, and footer sections of the Inputs page, respectively (see the review of hideInputs() above).

 
function showInputs(){ 
  hdrInputsVar.show(); 
  contentInputsVar.show(); 
  ftrInputsVar.show(); 
  hideProgress(); 
  hideResults(); 
  hideWide(); 
}

Function showResults()

For narrow-screen devices, the function showResults() shows the header, content and footer sections of the Results page and hides the Progress, Inputs, and Wide pages. Note that hdrResultsVar, contentResultsVar and ftrResultsVar are constants pointing to the <div> elements for the header, content, and footer sections of the Results page, respectively (see the review of hideResults() above). For wide-screen devices, showResults() provides no functionality.

 
function showResults(){ 
  if(isWide){ 
 
  }else{ 
    hdrResultsVar.show(); 
    contentResultsVar.show(); 
    ftrResultsVar.show(); 
    hideProgress(); 
    hideInputs(); 
    hideWide(); 
  }				 
}

Function showProgress()

For narrow-screen devices, the function showProgress() shows the header, content, and footer sections of the Progress page and hides the Inputs, Results, and Wide pages. Note that hdrProgressVar, contentProgressVar, and ftrProgressVar are constants pointing to the <div> elements for the header, content, and footer sections of the Progress page, respectively (see the review of hideProgress() above).

 
function showProgress(){				 
  if(isWide){ 
    resultsVar.html(TMP_INNER_HTML);					 
  } 
  else{ 
    hdrProgressVar.show(); 
    contentProgressVar.show(); 
    ftrProgressVar.show(); 
    hideInputs(); 
    hideResults(); 
    hideWide();				 
  } 
}

For wide-screen devices, resultsVar points to the <div> tag with id='resultsCell', representing the results grid. For wide-screen devices, this function sets the HTML content of resultsVar to constant TMP_INNER_HTML, which is defined as follows.

 
<div align="CENTER"> 
  <a href="javascript:try{requestObject.abort();resultsVar.html(EMPTY);}catch(err){};return false;"  
    data-inline="true" data-role="button" data-theme="b"  
    class="ui-btn ui-btn-inline ui-btn-corner-all ui-shadow ui-btn-up-b"> 
      <span class="ui-btn-inner ui-btn-corner-all"> 
        <span class="ui-btn-text">Cancel</span></span> 
  </a> 
</div>  
<div align="CENTER"> 
  <img src="css-js/images/wait.gif"/> 
</div>

The data-inline, data-role and data-theme attributes and values of various class attributes are all jQuery Mobile constructs.

The <a> tag has a jQuery Mobile button definition with a 'Cancel' label. From the review of getSearch() and getTweets() functions, recall that the global variable requestObject is set to the jQuery XMLHttpRequest object returned from the ajax calls to Twitter API. When that button is clicked, via inline definition of the JavaScript function, the jQuery abort() function is called on XMLHttpRequest object to end the ajax() call. In addition to the <a> tag with Cancel button, the HTML content defined above also contains the spinning wheel image wait.gif.

Function hideWide()

This function hides the header, content and footer sections of the Wide page. Note that hdrWideVar, contentWideVar and ftrWideVar are constants pointing to the <div> elements for the header, content and footer sections of the Wide page, respectively.

 
var hdrWideVar = $('#hdrWide'); 
var contentWideVar = $('#contentWide'); 
var ftrWideVar = $('#ftrWide'); 
... 
function hideWide(){ 
  hdrWideVar.hide(); 
  contentWideVar.hide(); 
  ftrWideVar.hide(); 
}

Function showWide()

This function shows the header, content, and footer sections of the Wide page and hides the Progress, Inputs, and Results pages. Note that hdrWideVar, contentWideVar and ftrWideVar are constants pointing to the <div> elements for the header, content and footer sections of the Wide page, respectively.

 
function showWide(){ 
  hdrWideVar.show(); 
  contentWideVar.show(); 
  ftrWideVar.show(); 
  hideProgress(); 
  hideInputs(); 
  hideResults(); 
}

Closing Remarks

In Part III, we continued inspecting the "Core Business Logic Functions" taking up from where we left off in Part II and finished the code review of the Tweets application by looking at "Event Handlers" & "Page Display Functions".

In the final part of this series, Part IV, I will start with the section named "Files In Download Archive", where we will describe the contents of the archive file accompanying this article. In "Environment Specific Topics", we will explain how to import the application into Eclipse for the Android platform and Xcode for the iOS platform. In that section, we will also give screen images of the application in an Android phone, an iPod touch, and an iPad 2. Finally, we will give concluding remarks and last thoughts for this project.