In the previous posts I have described roughly the idea which I implemented in order to learn some new techniques and a short architecture overview of the web application. Now I want to write a little bit about the framework Sugar JS which I developed for this application. It shows how easy it is with jQuery to write some custom AJAX behavior for your own application.
Before I start, let’s have a short walkthrough to the application. Initially it starts with an empty screen:

You see the title bar (“LISTS”), a grey text and a footer with the user information and a link to log out. The grey text reads “Create a new list”, and is in fact a text field in which you write the application name. Notice: no submit button, no borders, just plain text. This minimalistic design is by intention – maybe not the prettiest, but I like it (maybe I’ll change it later). But I wanted to let the user tap as less as possible, therefore there is no submit button. Once the user entered the text, the list gets created.


When tapping the list, its contents will be shown and can be edited. Same here: no submit buttons to reduce number of taps for the user. Here is a screenshot of an example list in edit mode:

You can see items added to the list (Apples, Milk) and raw items (Cheese). Items can have attributes (“2 bottles”). The idea behind this is: reuse items to avoid too much typing, but be flexible enough to change attributes of items.
Items can be deleted by swiping horizontally, which displays a delete button to the item, and to be more safe, a confirmation dialog is displayed when tapping on the delete button:

All this is handled by the Sugar JS framework. It provides:
- Display of a confirmation dialog on certain links; the selector can be specified for the links which should display the confirmation dialog. One example would be to use all links with the class “confirm”. When displaying the confirmation dialog, the text of the link’s title is shown.
- Handle form input and automatic submit when the user leaves the form
- Handle synchronous and asynchronous requests. The current implementation interprets all URLs, which start with a “!” as asynchronous request, regardless if it is in a link or a form action. This allows entering an attribute without reloading the page, as an example. It is also used when tapping on the items in the list (“tick”). This works quite well currently, but might get changed to a selector or class based solution later (e.g. all links/forms with class “async” will be handled asynchronously.
- Automatically extend text fields even while typing text.
All this is done inside of a static (i.e. non JSP) HTML page. To use Sugar JS, you need to include the sugar.js script and attach it to an element of your document. It can be the body element or any other element:
$(document).ready(function() {
$('body').sugar({
url : '/action/index',
submit : 'input.submit',
confirm : 'a.delete',
expand : 'input.attribute',
onLoad : function() {
$('a.checkin').click(checkin);
$('a.unticked').click(tickItem);
$('a.edit').click(toggleInNote);
...
});
The following initialization takes place:
$('body').sugar(...); initializes the Sugar JS framework and binds it to the body tag. The whole contents of the body tag will be replaced.
url : ... specifies the initial URL that is loaded into the tag, which the framework is bound to.
submit : ... specifies the selector of the elements that are enabled for automatic form submit. In this example all input fiels with class “submit”.
confirm : ... specifies the selector of elements that show a confirmation dialog when clicked (e.g. before deleting).
expand : ... specifies the selector of elements that are expanded while typing.
onLoad : ... is the place where custom Javascript will be added, which is executed after each synchronous load. This is required, to bind event handlers to DOM elements, which are have been loaded.
The custom functions you see (e.g. tickItem) mostly do some changes to CSS attributes to reflect changes on the screen based on user actions. But they can also handle more complex logic, such as the checkin function, which sends the geolocation to the server. My current implementation is quite a hack (and cries for improvement of the Sugar JS framework):
var checkinLink = undefined;
function checkin(event) {
event.preventDefault();
if (checkinLink == undefined) {
event.stopImmediatePropagation();
checkinLink = this;
navigator.geolocation.getCurrentPosition(function(position) {
var latitude = position.coords.latitude;
var longitude = position.coords.longitude;
doCheckin(latitude, longitude);
}, function(error) {
doCheckin(0, 0);
});
}
else {
checkinLink = undefined;
}
}
function doCheckin(latitude, longitude) {
var position = latitude + '/' + longitude;
var url = $(checkinLink).attr('href') + position;
$(checkinLink).attr('href', url);
$(checkinLink).click();
}
The problem with geolocation is: a) it is implemented asynchronously (so you cannot just say simply something like var position = getGeoLocation(), but instead you have to pass a function which gets called by the browser, and b) somehow the location has to be passed to the server, which I have handled by changing the URL of the link that has been clicked (yep, dirty hack) and then clicking it again to trigger the Sugar JS framework. I’m sure it can be done much better.
[Update] Now you might ask, what all this has to do with “request based” webapps. Now this is the deal with Sugar JS: Stripes Framework is request based, which means it handles only full page requests. If the user clicks a link, the whole page gets rendered. If the user submits a form, the same happens. Just by attaching Sugar JS to the page, it handles all synchronous and asynchronous requests.
The initial page is index.html. It is a normal HTML page with some Javascript (see above) and the body element looks like this:
<body>
</body>
It is empty. It will be populated by the Sugar JS framework on each (synchronous) request. The initially loaded page is configured by the url parameter (see above). Since Stripes provides some templating, here I have written an iphone.jsp template, which provides header, content and footer. It gets referenced by all other pages, such as index.jsp, note.jsp and edit.jsp. These pages are normal JSP pages without any Javascript; example: index.jsp:
<%@ page pageEncoding="UTF-8" contentType="text/html; charset=UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<%@ taglib prefix="s" uri="http://stripes.sourceforge.net/stripes.tld"%>
<s:layout-render name="/layout/iphone.jsp">
<s:layout-component name="title">Lists</s:layout-component>
<s:layout-component name="content">
<ul class="edgetoedge">
<c:forEach items="${actionBean.notes}" var="note">
<li><a href="/action/note/checkin/${note.id}/" class="checkin">${note.name}</a></li>
</c:forEach>
</ul>
<form action="/action/index/create" class="edgetoedge">
<input type="text" name="note.name" placeholder="Create a new list" class="submit"/>
</form>
</s:layout-component>
</s:layout-render>