HashCode

An organizer of symbols

Rails JsDOMenu

Para quem gosta da similiaridade de páginas web com desktop, aí vai um plugin para Rails com o estilo do Windows XP utilizando o clássico jsMenuBar. Isso me fez lembrar de um usuário que só conseguia operar o sistema por menus, link ficaria em um local obscuro da mente dele :-> .
O conceito é bem simples: cada menu pode ter MenuItens e Menus e uma MenuBar pode ter vários Menus.
Veja um menubar gerado com três menus e submenus.

menu1.png

Anatomia

O Rails JsDOMenu é composto pelos arquivos

/lib/menu_item.rb  # MenuItem
/lib/menu.rb       # Menu
/lib/menu_bar.rb   #MenuBar
/public/images/jsdomenubar/*.png    # imagens para os estilo
/public/stylesheets/jsdomenubar.css # o estilo.
/public/javascripts/jsdomenubar.js  # script da barra
/public/javascripts/jsdomenu.js     # script do menu.

Talvez o estilo da sua aplicações interfira diretamente no esboço do menu.

Instalação

Via svn
Adicione o repositório

script/plugin source svn://rubyforge.org/var/svn/railsmenubar/plugins

Depois instale com

script/plugin install railsmenubar

Via local
Descompacte o arquivo railsmenubar.zip no diretório vendor/plugins do seu Rails. Entre no diretório railsmenubar e execute

ruby install.rb

O jsDOMenuBar funciona em conjunto com os scripts de ajax e javascripts default do rails, portando adicione na sua view ou no seu layout os scripts

  <%= javascript_include_tag 'prototype' %>
  <%= javascript_include_tag 'effects' %>
  <%= javascript_include_tag 'dragdrop' %>
  <%= javascript_include_tag 'controls' %>

e depois o script e o css do railstree

  <%= stylesheet_link_tag 'jsdomenubar' %>
  <%= javascript_include_tag 'jsdomenu' %>
  <%= javascript_include_tag 'jsdomenubar' %>

ficando assim

  <%= stylesheet_link_tag 'jsdomenubar' %>
  <%= javascript_include_tag 'jsdomenu' %>
  <%= javascript_include_tag 'jsdomenubar' %>
  <%= javascript_include_tag 'prototype' %>
  <%= javascript_include_tag 'effects' %>
  <%= javascript_include_tag 'dragdrop' %>
  <%= javascript_include_tag 'controls' %>

Usando

Temos dois tipos de eventos(:event_type) o :code e o :link, sendo
:code => quando necessárioa execução de um script
:link => referência a uma url(default)
Veja abaixo como criar os dois tipos de eventos

m1=MenuItem.new "Mostrar mensagem de Oi!",
                 :event_type => :code,
                 :onclick => "alert('Oi!')"
m2=MenuItem.new "Ir para hashcode.eti.br",
                 :event_type => :link,
                 :onclick => "http://www.hashcode.eti.br"
#ou
m2=MenuItem.new "Ir para hashcode.eti.br",
                :onclick => "http://www.hashcode.eti.br"

Opções para o MenuItem
:label => A label do menu
:event_type => Tipo do evento :code ou :link
:onclick => Evento ou url
:enable => Habilita ou Desabilita (true ou false)
:icon => Path do ícone
:icon_hover => Path do ícone quando estiver selecionado

Criando um objeto Menu de tamanho 200px e adicionando o m1 e o m2

menu=Menu.new("Primeiro Teste", 200) #Label e o tamanho em pixel
menu << m1
menu << m2

ou passando um bloco

Menu.new("Primeiro Teste", 200) do |m|
 m << m1
 m << m2
end

Para finalizar esse exemplo vamos criar um MenuBar e adicionar o menu a ele.

mb=MenuBar.new :width => 300
mb << m

Já está pronto para ser utilizado.

Vamos dar nome aos bois

menu2.png

Que esboço maravilhoso esse!! Dá pra ver tanto que sou bom com o Gimp!! O que é aquilo lá em cima do MenuItem.separator ? É uma “quase uma seta”.

Mas dá pra entender um pouco.

Podemos ampliar o desempenho programático utilizando blocos. Exemplo de criação por fechamentos.

@menu=MenuBar.new(:width => 300) do |mb|
  mb << Menu.new("Primeiro Teste", 200) do |m|
    m << MenuItem.new("Ir para hashcode.eti.br", :event_type => :link, :onclick => "http://www.hashcode.eti.br")
    m << MenuItem.new("Mostrar mensagem de Oi!", :event_type => :code, :onclick => "alert('Oi!')")
  end
end

Observe algo interessante… a sintaxe acima tem uma semelhança com o esboço do menu, que ao meu ver induz ao programador o resultado a ser obtido, pois sabemos que criar menus é uma coisa carinhosamente chata.

Submenus

Como o estilo da linguagem é bem elegante vejamos a criação de submenus para o menu m.

@menu=MenuBar.new(:width => 300) do |mb|
  mb << Menu.new("Primeiro Teste", 200) do |m|
    m << MenuItem.new("Ir para hashcode.eti.br", :onclick => "http://www.hashcode.eti.br")
    m << MenuItem.new("Mostrar mensagem de Oi!", :event_type => :code, :onclick => "alert('Oi!')")
    m.new("Sub 1") do |s1| #método da instância
      s1 << MenuItem.new("Item 1!", :event_type => :code, :onclick => "alert('item 1')")
      s1 << MenuItem.new("Item 2!", :event_type => :code, :onclick => "alert('item 2')")
   end
 end
end

pode simplificar mais ainda, utilizando os façade de cada objeto. O mesmo código anterior utilizando façades.

@menu=MenuBar.new(:width => 300) do |mb|
  mb.new("Primeiro Teste") do |m|
    m.new_item("Ir para hashcode.eti.br", :onclick => "http://www.hashcode.eti.br")
    m.new_item("Mostrar mensagem de Oi!", :event_type => :code, :onclick => "alert('Oi!')")
    m.new("Sub 1") do |s1|
      s1.new_item("Item 1!", :event_type => :code, :onclick => "alert('item 1')")
      s1.new_item("Item 2!", :event_type => :code, :onclick => "alert('item 2')")
    end
  end
end

E que Deus continue inspirando Yukihiro Matsumoto
Vc escolhe!
Temos também o MenuItem separador.

m=Menu.new("Primeiro Teste", 200)
m <<MenuItem.separator

Um MenuBar com dois menus seria algo assim

@menu=MenuBar.new(:width => 300) do |mb|
  mb.new("Primeiro") do |m|
    m.new_item("Ir para hashcode.eti.br", :onclick => "http://www.hashcode.eti.br")
    m.new_item("Mostrar mensagem de Oi!", :event_type => :code, :onclick => "alert('Oi!')")
    m.new("Sub 1") do |s1|
      s1.new_item("Item 1!", :event_type => :code, :onclick => "alert('item 1')")
      s1.new_item("Item 2!", :event_type => :code, :onclick => "alert('item 2')")
    end
  end

  mb.new("Segundo") do |m|
    m.new_item("Faça algo 1", :onclick => "http://www.hashcode.eti.br")
    m.new_item("Faça algo 2", :event_type => :code, :onclick => "alert('algo 2')")
    m.new("Sub 1 do Segundo") do |s1|
      s1.new_item("Item Sub1 1!", :onclick => "http://www.hashcode.eti.br")
      s1.new("Sub 2 do Segundo") do |s2|
        s2.new_item("Sub2 1", :onclick => "http://www.hashcode.eti.br")
        s2.new_item("Sub2 2", :onclick => "http://www.hashcode.eti.br")
      end
      s1.new_item("Item Sub1 2", :onclick => "http://www.hashcode.eti.br")
    end
  end
end

Link for Rails

Tem um esquema legal que é usar a mesmo mecanismo de link do rails o link_to e o link_to_remote.
É necessário a adição da opção :base referenciando a uma instância de qualquer controller(geralmente self ou @controller) para que o mecanismo do método url_for do Rails funcione adequadamente.

link_to

item1=MenuItem.new
item1.link_to "Criar usuário",
              :base => self,
              :controller => "usuarios",
              :action => "adicionar" ,
              :id => 1

m=Menu.new("Usuário")
m << item1

ou

item1=MenuItem.new.link_to "Criar usuário",
              :base => self,
              :controller => "usuarios",
              :action => "adicionar" ,
              :id => 1
m=Menu.new("Usuário")
m << item1

ou tudo junto!!

Menu.new("Usuário").new_item.link_to "Criar usuário",
              :base => self,
              :controller => "usuarios",
              :action => "adicionar" ,
              :id => 1

Dá até gosto de programar nessa linguagem!!

link_to_remote

Utiliza-se ajax da mesma forma que o link_to mas com parametros diferentes(claro né Shairon!).
Exemplo:

item1=MenuItem.newitem1.link_to_remote "Teste Ajax",
                      :base => self,
                      :controller => "usuarios", :update => "id_do_div",
                      :url =>{:action => "adicionar",
                              :c=> 'variavel C',
                              :a => 'variavel A'}

Use e Abuse!!