I am currently converting my GIS application that needs two browser windows (one for the map, and one for the administrative data and functions), to a single window application using the netzke gems (which in turn rely on Sencha Ext js).

The netzke gems are extremely powerful, but there is a bit of learning curve for me, since both netzke and ext js are new. But netzke makes a lot of things a lot easier. It is not really rails-like, since it abstracts a lot away, and I am not yet completely convinced of the approach. But for my current goals it is ok.

I have a panel containing an openlayers map, and a toolbar with action buttons. The action buttons need to indicate state (drawing/measuring). So when clicked they have to be in a “pressed” state, and start with the action.

Although I found no example of this, achieving it was pretty easy. I defined my action buttons as follows:

action :measure_line do |c|
  c.id = "measure_line"
  c.icon = :ruler
  c.text = ""
end

action :measure_area do |c|
  c.id = "measure_area"
  c.icon = :surface
  c.text = ""
end

js_configure do |c|
  c.layout = :fit
  c.mixin
end

def configure(c)
  c.desc = "Contains the openlayers map"
  c.title = "Map"
  c.tbar = [:draw_point, :draw_line, :draw_polygon, :measure_line, :measure_area, :navigation_history]
  c.body_padding = 5
end   

I am only showing the actions for :measure_line and :measure_area because these are now the relevant ones I want to show. I need to give explicit id to the buttons, so that I can use Ext.ComponentManager.get to find them later on.

Nice thing to know is that the action handler by default receives the pressed button (yes!). This will allow us to just toggle it. So your mixed in javascript will look this:

{
    onMeasureLine: function(btn) {
      Map.toggleMeasuring(btn, 'line');
    },
    onMeasureArea: function(btn) {
      Map.toggleMeasuring(btn, 'polygon');
    },
}

Because I prefer to write coffeescript (not found how I can do that for the netzke mixins), I have a class Map in map.js.coffee containing all map-related functions. toggleMeasuring needs the button and the measurement-action to activate/deactivate

toggleMeasuring: (button, measurement_type) ->
  button.toggle()
  if 'pressed' in button.uiCls
    @measureControls[measurement_type].activate()
  else
    @measureControls[measurement_type].deactivate()

  # make sure the other measuring is automatically switched off
  for  key of @measureControls
    unless key == measurement_type
      @measureControls[key].deactivate()
      Ext.ComponentManager.get("measure_#{key}").toggle(false)

That is about the gist of it. I will be sharing more of my netzke experience and code soon. For the moment still impressed :)