For a not so much recent project I needed to create a standalone widget that can be displayed on any page with less effort.
You can see the result here (don't forget to view source). And if it seems interesting to you, keep on reading :)
The Idea is to create a standalone widget for your application that can be used easily on any other site.
Think of it as minifying your app where cool stuff are happening :)
Apotomo - which separates the stuff
that you need and you get a much
cleaner code, hence the speed.
Apotomo comes with many othercool
stuff, I recommend that You check
out the tutorials
http://apotomo.de. I'll explain
later why I've decided to use
for writing pure js....and using a
framework may have conflicts with
the clients js, and widgets need to
be independent. The js that is used
is inspired from the twitter widget.
Create new rails 3.0.3 app - there is an issue with json serialization in previous rails versions, the to_json method does not return the required structure.
- Add haml+compass in your Gemfile :)
Create new apotomo widget with
rails generate apotomo:widget apotomo_widget display_form --haml
Create/Use the models from your
application so you can get the data that you want to show in the widget.
I've created a simple PostLink model that has title and url.
There is also a rake task that gets the titles and urls from apotomo's feed and stores them in db.
Set up the widget display action -
see source in haml.
After the display action for the widget is defined we can add some styling, but we also want the client to be able to set a theme for our widget.
At first, I've defined different css for every theme that is used when the widget is initialized, but I've depricated that code and I've decided to put
all the styling for different themes in one file. My css skills are .... :) anyway you can check the styling for some themes that I've set here
It's js time
Ok, we've set the display action for the widget, now it's time to create a widgets controller and write some js, so:
- Create a widgets controller that
responds to the index action with js
- set: match "widgets", :to =>
"widgets#index" in routes.rb
- Create index.js.erb in
class WidgetsController < ApplicationController
has_widgets do |root|
root << widget(:apotomo_widget, 'apotomo_widget', :display)
respond_to do |format|
You can check the end result here.
At first I've defined some helper methods that are used through the code. JsonP is used for getting data from the server..css and data that we want to display.
Every widget has it's own istance which is known by the widget_number, and it's own refresh_interval.
For this example I've added options for refresh_interval and theme to be set by the client.
After the widget is initialized the autoRefresh() function is called which updates the widget data.
So how do we get the data from the server?
This is the why apotomo part kicks in....despite the number of widgets that we can create using Apotomo, all apotomos widgets
will respond with the action that we've requested: so for example if we have lets say 3 apotomo widgets (first_widget, second_widget, third_widget)
they'll all respond to /widgets/render_event_response action where as arguments we specify on which widget(source), which action(type) we want to call.
In this example: we request for: &source=apotomo_widget&type=update
This will call the update action in apotomo_widget...which we use to execute our callback.
text = params[:callback] + '(' + PostLink.all.to_json + ')'
render :text => text, :content_type => 'application/json'
Unfortunately Apotomo does not accept the :callback parameter :( ...usually the rails way we simply need to call:
render :json => PostLink.all, :callback => params[:callback]
The callback parameter in this example looks like this APOTOMO.Widget.updatePosts_1 for the first widget instance,
which updates the widget data for the widget that requested
At the end
Now all that we need to do is to include our js(path to our widgets/index action) on any page and create the widget/widgets instances. This can be done on any web page, all that
needs to be entered is:
And where we want the widgets to show we simply put