This article is the second of two articles about a hobby project in Rails I call Clouds. The concept of the application and the backend are described in part 1, and you can try a demo here. In this article we turn to the most advanced part of Clouds; it’s use of the javascript libraries Prototype and Scriptaculous to allow the user freely add, edit, move and delete topics while keeping the backend database up to date.
From .rhtml to .js
When a user enters the site a new cloud automatically gets created, and the user is redirected to the edit action of clouds_controller. The layout file of the clouds_controller includes required stylesheets as well as the standard javascripts (Prototype, Scriptaculous and application.js where the Cloud-specific code is placed). It also defines the common menu of the new and edit actions, while <%= yield :menu_items %> allows each of the actions to also define their own menu items through <% content_for :menu_items do %>.
Take a look at edit.rhtml. At the top is a javascript block which defines an object called Server, where information about which urls to use when making AJAX calls and the id of the cloud being edited are placed. Also, in the init javascript function a call the to Topic.topic_attach function is generated for each topic belonging directly to the current cloud (inherited topics cannot be edited). Topic.topic_attach sets up events that allows the user to move, edit and delete the topic. The javascript block also calls Cloud.init upon load, which sets up an event that allows the user to create a new cloud by double-clicking anywhere on the page.
The code inside <div id="cloud_body"> illustrates an important choice I had to make: Should I render existing topics and a template for new topics server-side, or should I output the topic details in - say - the call to Topic.topic_attach and generate the html for the existing topics client-side? While the latter might seem be DRY'er, I opted for the former solution because it has two immediate advantages: The browser renders the page faster from server-generated html, and I am able to control the html from partials instead of through messy DOM code.
Javascript structure and naming conventions
The core of Clouds; application.js, consists of four objects with a number of functions. Many functions are invoked by a certain user-generated event, while others serves as helper-functions to these. Only Cloud.init and Topic.topic_attach are invoked from the "outside". The event-handling functions uses .NET naming conventions; the name of source element, and underscore, and the name of the event being handled.
The Cloud object handles only events related directly to the overall "cloud", mainly the creation of new topics - which is passed on to the Topic object - and changing the title of the Cloud the AJAX'y way. The Topic object is where the real action is; creating, moving, editing and deleting topics, and I discuss the functions of this object in detail in the following section.
The Sync object demonstrates how to make AJAX calls to a RESTful Rails backend. The functions all uses the Ajax.Request class, but while topic_create_server and cloud_update_server are able to use request urls directly from the Server object, the functions for updating and destroying topics needs a url with the id of the specific topic being manipulated. I've chosen to let the container div element of each topic have an attribute called update_url, allowing the backend to stay in control of all urls instead of constructing them in javascript. Notice the contents of the parameters argument to each call to Ajax.Request: I use the topic[attribute_name] naming convention of Rails to be able to treat the AJAX call like any other request on the server-side, and I add the RESTful "cheating" variable _method the code>parameters argument when updating (_method=put) and deleting (_method=delete) a topic or a cloud.
Finally the Helper object provides various more or less "generic" helper methods. readAttribute and setAttribute are handy shorthand methods for manipulating html attributes cross-browser, while insertInput and removeInput are handy methods for transforming a div element with some text inside into an input field with that text, and back again.
Manipulating topics
When the user double-clicks anywhere on the page, the function topic_create_client in the Topic object are invoked with the position of the mouse as arguments. This function clones the template generated in clouds/edit.rhtml from the topics/_topic.rhtml partial, assigns a temporary client-side id to the new topic (the topic is not created server-side until the user has written some text and hit enter), positions the topic, adds it the to page, attaches events to it and makes it editable.
When the user hits enter in the input field of the new topic or removes focus from the field, the topic_blur function is invoked. This method transforms the input field back to a div with the new text inside, and makes sure the topic is either created, updated or deleted server-side, if the topic has no id, has one or the text is blank, respectively. When the user double-clicks the text of an existing topic topic_doubleclick once again makes the input field appear, but it also makes sure that the double-click does not bubble up to the parent cloud element by calling Event.stop(e). If the event wasn't stopped here, a new topic would be created on top the one being edited.
The function topic_set_id plays a vital role: As mentioned, new topics are assigned a temporary client-side id, but once the topic is created server-side, we need it to know the server-side id so it can be supplied when the user manipulates the topic. Sync.topic_create_server are invoked when a topic is to be created server-side, and by passing onComplete: Topic.topic_set_id to the request object, this function is called with information about the request (transport) and the data returned by the request (json). Take a look at line 44 of clouds_controller:
format.js { render_json({ :client_id => params[:client_id], :server_id => @topic.id }.to_json) }
This results in the create action, when invoked with AJAX, returning a very nice JSON object with information about the topic's current id assigned by the client, and it's new, "real" id assigned by the server. The JSON data looks something like this, and by magic of Prototype, it is readily available to use when the function is invoked:
{client_id: "0", server_id: 176}
From that information topic_set_id are able to assign a new id to the topic, decided by the server.
Rounded corners and hovering
I also want to mention a few of the visual aspects of Clouds. First of all I really like to smooth boxes up a bit by giving them rounded corners, and while this as quite easy to achieve using four images, a bunch of div-elements and a considerable amount of CSS, I opted for a easier and more flexible solution. I use the javascript library NiftyCorners which, with just a single javascript call, applies rounded corners to all elements identified by a given selector. The thing that is so nifty about NiftyCorners is that I don't have to create any graphics myself, and I can continuously change the size and the color of the corners - again without having to make new graphics and change a bunch of CSS.
Another visual aspect of Clouds is that the box and the textarea for entering notes only appear when the user hovers his or hers mouse above a topic. Curiously I have opted not to use javascript to handle this, although I have experimented a lot with it. The problem with using javascript is that it is quite complex to figure out which topic that should have it's class changed, since the source element of the mouseover and mouseout event are rather unpredictable. Prototype and Scriptaculous are not able to abstract away the fact that different browsers chooses to fire these events differently, and this makes the CSS alternative very attractive.
Looking at the stylesheet you'll see that I've simply added a bunch of :hover classes which makes the "box" and the textarea for notes appear upon hovering. The only problem I encountered when implementing hovering this way was the corners added by NiftyCorners didn't appear and disappear as they should, but with a little from one of my favorite Firefox plugins - WebDeveloper - I easily found the classes of the added div elements that also needed to have hover classes added:
.rtop,.artop{visibility:hidden}
div.topic:hover .rtop, div.topic:hover .artop, div.topic.active .rtop, div.topic.active .artop {visibility:visible}
Another plugin without which I'd never been able to debug all the AJAX communications and client-side event handling is of course FireBug. If you are developing anything using AJAX or javascript in any other way, you seriously need to install and actively use this plugin. If you are developing web applications and uses Safari or Internet Explorer as your primary browser you seriously need to consider if you are as productive as you could be. Heh.
Conclusion
Back again from that little telling-off (don't know what went into me), I want to conclude this article series by underlining that Clouds in it is current state is not ready for production, as it does not function properly in Internet Explorer. If you decide to go ahead and use some of the code anyway, I would of course love to hear from you. Happy hacking.
Hello, I'm Casper Fabricius. I have developed for the web for 9 years, and have been enjoying Ruby on Rails for the past 4.
My experience covers communities, shopping solutions, multi-language sites, heavy back-end lifting and a wide selection of more traditional websites. I like to integrate Ruby with Java and .NET through JRuby and IronRuby when it makes sense. I am passionate about test- and behavior-driven development, but at the same time I am pragmatic and believe in getting things done.
I am based in Copenhagen, Denmark, but I take assignments from across the globe. Feel free to study my resumé, featured projects and - of course - to hire me.
buy paxil canada
buy viagra without a prescription
cheap levitra online
cheap discount soma
buy viagra pharmacy online
cheap discount levitra online
premarin
buy viagra now online
buy legal fda approved viagra
cheaper viagra levitra cyalis
buy medved viagra
discount viagra brand drug
discount viagra in the usa
buy viagra softtabs
buy viagra on line
buy cheap generic viagra
buy online viagra securely
buy viagra next day delivery
cheap online pill viagra
buy lasix
viagra canada prescription
viagra and cialis and
buy discount zoloft
cheap crestor online
buy buy cheap viagra
cheapest price for viagra
cheap pill viagra
buy sildenafil viagra
buy in online uk viagra
cheap cialis viagra
cheap drug retin viagra wellbutrin
order viagra licensed pharmacies online
buy viagra from brazil
cheapsest viagra online
cheap order prescription viagra
buy form generic viagra
buy viagra at safeway
cheap deal discount viagra viagra
cheapest viagra online in the uk
cheapest viagra uk
buy hgh now
buy crestor now
buy viagra in the philippines
buy generic online viagra
cheapest online viagra
order forms for buying viagra
cheapest generic silagra viagra
buy caverta
buy cheap cialis
buy now online viagra
buy cialis canada
buy viagra online 350
order prescription viagra
discount viagra sale
buy viagra from an online pharmacy
order generic viagra
cheap cheap viagra
cheap cheap herbal viagra viagra viagra
viagra by mail order
buy viagra low cost
order viagra usa
cialis 32
buy cheap soma
buy viagra cialis
cheapest viagra in uk cheap
buy online online pill viagra viagra
buy internet viagra
cheap online pharmacy viagra viagra
buy cheap discount levitra
cheap online purchase viagra
buy viagra onlines
buy real viagra pharmacy online
cheapest cialis
buy viagra and cilas usa
buy viagra online order
over the counter viagra in europe
cheap viagra online uk
viagra bullshit
buy viagra online 35008 buy
buy drug satellite tv viagra
viagra breathing
cheap generic india viagra
buy discount viagra online
cialis 1
buy crestor online
discount viagra cialis
buy viagra meds online
buy viagra ups
buy online viagra viagra
soma online
buy generic viagra online pharmacy online
buy viagra online without prescription
cheap viagra kamagra
cheap quality viagra
cheep viagra from indea
buy viagra inte
buy viagra online u
order viagra on line
buy pharmaceutical viagra
viagra and discovery
buy viagra levitra alternative lavitra
cheapest in uk viagra
buy herbal viagra
order viagra onlines
viagra buying online
buy viagra and overseas
buy cheap viagra on the net
cheapest brand viagra
cheap levitra online
buy hgh canada
buy cheap deal pill viagra
order viagra buying viagr
buy plavix
discount viagra generic
viagra buy viagra
buy viagra for cheap
buy viagra in england
buy deal herbal viagra viagra
cheap referrers total viagra
buy cheap cialis generic levitra viagra
order site viagra
cheapest viagra us pharmacy
buy viagra online australia
buy viagra for women
buy kamagra
discount viagra mastercard
cheap discount viagra
cheep generic viagra
buy isoptin
cheap viagra discount viagra buy viagra
buy cialis without prescription
cheap viagra uk
cheapest viagra world
discount viagra viagra
buy viagra in the uk
buy viagra per pill
discount viagra or cialis
cheap overnight viagra
buy viagra now
discount viagra drug
buy lipitor
order order viagra
buy viagra order viagra
discount viagra offers
buy p viagra
cheap kamagra uk viagra
cheapest viagra online plus zenegra
cheap viagra 25mg
buy viagra without prescription
buy in uk viagra
buy generic viagra pharmacy online
buy levitra viagra online
cheap molde ticket viagra
cheapest price viagra
cheapest viagra us licensed pharmacies
viagra and coupon
buy viagra viagra online
order viagra with mastercard
cheap no prescription viagra
cialis online
buy viagra online web meds
viagra buy uk
cheapest price for viagra and cialis
viagra and cialis cheap
generic soma
buy cheao cgeap kamagra uk viagra
buy levitra online viagra
buy prescription viagra without
buy viagra no prescription
buy cheapest online place viagra
buy viagra online online pharmacy
purchase levitra
buy levitra now
purchase levitra online
order levitra online
cheap viagra no presrciption 50mg
buy viagra where
buy online p viagra
buy online purchase viagra
buy viagra 100mg
cheapest generic viagra caverta veega
buy cheap viagra 32
buy online viagra in the uk
viagra by mail
purchase tramadol online
discount viagra prescription drug
buy cheap site viagra
buy viagra zenegra
buy softtabs viagra
over the counter viagra substitute
order viagra online consumer rx
cheap levitra viagra href foro forum
viagra buy it
buy cheap crestor
buy viagra or cilas
order mexican viagra
buy now viagra
buy crestor
buy viagra australia
cheap mexico viagra
buy viagra online india
order viagra online a href
cheap viagra canada
cheapest generic viagra and cialis
buy viagra online no prescription
cialis 20mg
allegra d
cheap deal pill pill viagra
buy viagra online now buy viagra
viagra buy now pay later
buy lexapro
buy viagra alternative
cheap phizer viagra
viagra buy in uk online
order crestor
cheap drug online prescription viagra
generic zoloft
imitrex
buy deal deal price viagra
buy viagra in uk
viagra and deafness
buy viagra cheap through online sales
cheap prescription viagra without
cheap viagra in uk
buy viagra 32
cheap testosterone viagra href foro
buy keyword viagra
order zoloft online
cheap generic viagra substitutes
buy discount soma
buy viagra contact us page
buy canada viagra
buy viagra in mexico
buy australian viagra
cheapest line viagra
order discount viagra
cheap pharmaceutical viagra
order 50mg viagra
viagra buy contest
buy levitra
buy viagra online discount
tramadol cod
cheapest generic viagra and cialis pills
buy viagra online alternative viagra
order crestor online
buy viagra over the counter
buy dot phentermine viagra
buy deal viagra
cheap online generic viagra
buy online sale viagra
buy viagra cheap fed ex
buy avandia
buy glucophage
buy viagra in spain
cheapest prices on generic viagra
buy non prescription generic viagra paypal
zoloft online
cheap meltabs viagra
buy cheap discount lexapro
order viagra softtabs
buy viagra buy cheap viagra index
buy cipro
cheap genric viagra online
generic levitra
buy viagra toronto
cheaper viagra
buy depakote
buy free viagra viagra
buy cheap uk viagra
viagra buy general
cheap viagra cialis
cheap discount soma online
cheap generic viagra from usa
purchase crestor online
buy cheap discount pill viagra viagra
seroquel
cheapest viagra on line
buy viagra safeway pharmacy
buy cheap viagra online uk
cheap soft tab viagra
order status viagra
cheap testosterone viagra href foro forum
cheap drugs viagra cialas
buy now soma
buy crestor
cheap discount cialis
order pfizer viagra with mastercard
cheap viagra credit
cheapest generic substitute viagra
viagra buy australia
cheap viagra online order viagra now
buy viagra in bangkok
buy viagra over the counter us
buy cheap viagra online now uk
buy cheap purchase uk viagra
cheapest viagra and regalis
cheapest generic viagra 99 cents
buy cailis viagra singapore
cheapest viagra prices uk
cheap crestor
purchase crestor
order viagra prescription
viagra and flomax
buy followup post viagra
buy generic viagra online
buy online online viagra viagra
viagra buy
purchase paxil online
order viagra now
cheap viagra
buy carisoprodol no prescription
purchase nexium online
order viagra online in wisconsin
buy in spain viagra
cheap viagra index
over the counter viagra alternative
buy sublingual viagra on the internet
buy imitrex
order viagra overnight shipping
cheap viagra online prescription
buy cheap p viagra
buy viagra with paypal
viagra canada price
buy viagra line
cheap cheap viagra viagra
buy viagra in london
viagra by money order
discount viagra overseas
viagra by phone
buy viagra in toronto
buy cheap levitra
cheapest place to buy viagra online
check generic order pay viagra
buy uk viagra
cheap viagra from pfizer
buy online pill viagra
buy generic viagra si br
buy pill price price viagra
buy generic viagra usa
cheap gerneric viagra
buy cheap online prescription viagra
cheaper viagra levitra apcalis
buy cheap viagra online here
buy viagra phentermine online pharmacy
buy discount price sale viagra viagra
buy discount crestor
buy viagra online cheap
viagra buy do nu
buy viagra by pill
over the counter viagra
buy cheap viagra online now
buy evista
cheap herbal sale viagra viagra
buy cheap lexapro
buy viagra online 35008 buy viagra
buy viagra without prescription pharmacy online
lexapro side effects
buy cheap free online viagra viagra
buy cheapest viagra
cheap discount levitra
cipro 20
cheap viagra fast shipping
relafen
buy online prescription viagra without
buy can reply viagra
buy site viagra
cheap deal viagra
buy online order viagra
cheapest uk supplier viagra
buy viagra in amsterdam
cheapest viagra in uk che
buy cheap sale viagra
order viagra online no rx prescription
buy soma
discount viagra
buy diet viagra online
buy neurontin
buy viagra new york
buy now hgh
cheap discount crestor online
buy online viagra viagra viagra
cheap paxil online
buy levitra canada
buy prescription viagra
discount viagra perscription drug
cheap herbal viagra viagra viagra
buy cheap online uk viagra
buy viagra in united kingdom
buy cheap viagra viagra
buy coumadin
viagra and cialas
cheapest viagra on the internet
cheap discount crestor
cheapest generic viagra sent overnight
buy viagra online get prescription
buy locally viagra
viagra by mail catalog
cheapest viagra overnight