miércoles, 21 de septiembre de 2011

Using JSNI in GWT

Se puede combinar fácilmente código JavaScript directamente en el código de GWT. Es todo JavaScript al final. Eso es acerca de lo que JSNI se trata. Es un nombre similar al Java Native Interface (JNI), ya que utiliza la misma idea básica: declarar un método Java "nativo" y luego usar otro lenguaje para implementarlo. En el caso de JSNI, ese otro lenguaje es JavaScript. :)

A los ejemplos...

Podemos mostrar un alert como usualmente lo hacíamos con JavaScript .. alert('This is an alert!');


public class MyApp implements EntryPoint {

     public void onModuleLoad() {

         Window.alert(’Showing alert from GWT’);
         showAlert("Some string...");

     }

     public native void showAlert(String param)/*-{

         $wnd.alert('Showing alert from JavaScript' + param);

     }-*/;

}

También podemos hacer el camino inverso... invocar métodos de Java desde JavaScript utilizando JSNI

public class BlueApp implements EntryPoint {

     public void onModuleLoad() {

          setShowTrigger(this);

     }

     public void runApp() {

          Window.alert(’I am a GWT function’);

     }

     public native void setShowTrigger(BlueApp x)/*-{

          $wnd.showBlueApp = function () {

               x.@com.company.client.BlueApp::runApp()();

          };

     }-*/;

}

Cuando se carga el módulo se crea una función JavaScript llamada showBlueApp(), y nada más. Esa función puede ser invocada desde la página HTML, ahí se ejecutará el método runApp(). Este está referenciado en JavaScript con su path completo el cual incluye además el nombre del módulo. La variable x es la clase misma y es enviada como parámetro usando “this”. Una vez invocado el alert aparece.
La función showBlueApp debería ser invocada como cualquier otra función JavaScript desde el HTML.


onclick="showBlueApp()"
   
Links útiles: - Tutorial en PDF
              - GWT Blog Article

Saludos. =)


miércoles, 7 de septiembre de 2011

GWT MenuBar - Handling Keyboard Events

Este problema se me presentó ayer y me parece bueno aportar en esto ya que todo lo que sea Menu/MenuBar/MenuItem en GWT no parece tener buen manejo de handlers, buen.. en cuanto a MenuItem directamente no lo tiene.

El problema en sí es el siguiente: ¿Que pasa si yo quiero capturar eventos del teclado junto con el click en algún item del menu?... El constructor de MenuItem espera un Command el cual va a ser ejecutado cuando se hace click en dicho elemento, pero no da la posibilidad de capturar otros eventos como Doble click, o teclas como Ctrl., Alt., Shift, etc.

La solución que encontré puede que no sea la mejor, pero resuelve el problema (:

Primero que nada creamos la clase MenuBarAdv que extiende de MenuBar


/**
 * MenuBarAdv.java
 * 06/09/2011 12:28:52
 * @author Cristian N. Miranda
 */
package ar.com.gwt.menu.events.client;

import com.google.gwt.core.client.GWT;
import com.google.gwt.user.client.DOM;
import com.google.gwt.user.client.Event;
import com.google.gwt.user.client.ui.MenuBar;

/**
 * @author Cristian N. Miranda
 */
public class MenuBarAdv extends MenuBar {

 private boolean ctrlKeyPressed;
 
 /**
  * Constructor
  */
 public MenuBarAdv() {
  super(false);
 }

 /**
  * Creates an empty menu bar.
  * 
  * @param vertical
  *            < code >true< /code > to orient the menu bar vertically
  */
 public MenuBarAdv(boolean vertical) {
  super(vertical, GWT.< Resources > create(Resources.class));
 }

 @Override
 public void onBrowserEvent(Event event) {
  MenuItemEvents.setCurrentMenuBarAdv(this);
  switch (DOM.eventGetType(event)) {
  case Event.ONCLICK: {
   if(event.getCtrlKey()){
    ctrlKeyPressed = true;
   }else{
    ctrlKeyPressed = false;
   }
   break;
  }
  }
  super.onBrowserEvent(event);
 }

 /**
  * Get Ctrl. Key Pressed Status
  * @author Cristian N. Miranda
  * @return
  */
 public boolean getCtrlKeyPressed(){
  return this.ctrlKeyPressed;
 }
 
}

Ahí es donde capturamos los eventos que se generen sobre el MenuBar con el método onBrowserEvent() ...

Luego en nuestro EntryPoint..

package ar.com.gwt.menu.events.client;

import com.google.gwt.core.client.EntryPoint;
import com.google.gwt.user.client.Command;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.ui.MenuItem;
import com.google.gwt.user.client.ui.RootPanel;

public class MenuItemEvents implements EntryPoint {
 
 private static MenuBarAdv currentMenuBarAdv;
 
 private final MenuBarAdv menutop = new MenuBarAdv();
 private final MenuBarAdv menutwo = new MenuBarAdv(true);
 
 public void onModuleLoad() {
 
  // A command for general use
  Command command = new Command(){
   @Override
   public void execute() {
    Window.alert("Ctrl. key pressed: " + String.valueOf(currentMenuBarAdv.getCtrlKeyPressed()));
   }
  };
  
  // Top-level menu
  menutop.addStyleName("demo-MenuItem");

  // Item to fire a command
  MenuItem fireone = new MenuItem("Fire One", command);

  // Level-two menu - vertical=true
  
  menutwo.addStyleName("demo-MenuItem");

  // Items for menu two
  MenuItem firetwo = new MenuItem("Fire Two", command);
  MenuItem firethree = new MenuItem("Fire Three", command);
  MenuItem firefour = new MenuItem("Fire Four", command);
  
  // Assemble the menu system
  menutop.addItem(fireone);            // Adds existing item
  menutop.addItem("SubMenu", menutwo); // Creates item and adds menutwo
  menutwo.addItem(firetwo);
  menutwo.addItem(firethree);
  menutwo.addItem(firefour);
  
  RootPanel.get().add(menutop);
  
 }
 
 /**
  * Obtains the current MenuBar clicked
  * @author Cristian N. Miranda
  * @param menuBarAdv
  */
 public static void setCurrentMenuBarAdv(MenuBarAdv menuBarAdv){
  currentMenuBarAdv = menuBarAdv;
 }
 
}

Ahi es donde obtenemos la instancia del MenuBarAdv clickeado y verificamos los flags de las teclas o cualquier otro evento deseado.. todo dentro de nuestro método execute() del Command para cada MenuItem.

Post en Google groups haciendo referencia al problema: http://code.google.com/p/google-web-toolkit/issues/detail?id=3559 (Titulado: MenuItem should better use ClickHandler instead of Command)
Código de ejemplo: http://code.google.com/p/gwt-menuitem-keyboard-events/downloads/list

Cualquier cosa avisan.
Saludos.

CKEditor Wrapper

Wrapper para GWT del editor de HTML "CKEditor" http://ckeditor.com
Es muy fácil de integrar a cualquier proyecto.. pueden seguir los pasos en el proyecto de Google code. (http://code.google.com/p/gwt-ckeditor/). Además de seguir todos los pasos, a los autores se les pasó por alto lo siguiente, para hacer que funcione correctamente (incluyendo en Dev mode) hay que agregar lo siguiente en nuestro App.html..

<script type="text/javascript" language="javascript" src="cksample/ckeditor/ckeditor_source.js"></script>
Les va a quedar algo así..



Acá un proyectito de ejemplo con los fuentes del Wrapper en caso de que no quieran usar la librería: http://code.google.com/p/gwt-ckeditor-wrap/downloads/list

Cualquier cosa chiflan.
Saludos. (: