miércoles, 31 de octubre de 2012

Using YUI in GWT UIBinder

About this document 

This document try to document a new feature of the toolkit YUIGWT for using YUI markup in GWT UIBinder.  It will no try to teach you how to use neither YUI or YUIGWT or GWT UIBinder (the user is supposed to know the basics of these technologies).

Online tests


YUIGWT example gallery contains the first tests related to using YUIGWT and UIBinder. The examples are:
  • uibinder test 1 - contains some yui widgets and GWT widgets mixed - layouting using YUI cssgrids.
  • just one, making more for the 1001 usescase... stay in touch....

Introduction

In GWT applications it is common to use UIBinder to separate the markup and style (design) from Java code (behavior).

And YUI proposes a very similar thing. All YUI widgets can be created from a markup structure. This markup structure is defined by each YUI widget. Some simple widgets like Y.Button only requires you to give a <button> element, but other more complicated YUI widgets like tabview, treeview, etc need you to provide a more complex markup (example).  This is somehow related to yui philosophy's of "Progressive Enhancement" @see http://yuilibrary.com/yui/docs/tutorials/gbs/

UIBinder users can mix both GWT Widgets markup and plain HTML Markup in their UI. Also the user is able to bind some of these markup elements to actual Java Objects fields in its Java code where the behavior, controller and modeling of the application is written.

In this document we will discuss how to use YUI Widgets proposed markup together with GWT UIBinder for rendering YUI components using UIBinder in a YUIGWT application.

Solution Summary

In general, the solution proposed here is the user to write YUI plain HTML markup for its YUI widgets in the UIBinder ui.xml, and mark them with an special class name for indicating the framework that that HTML element is a YUI widget and must be "post rendered". Then the user binds these widget elements in the UIBinder java's and after creating the UIBinder main Widget, ask the framework to render all the YUI elements. Later in the code, the user can ask the framework to return the appropiate YUIGWT Widget java class from a certain html element for work with the widget in Java. Hope this can be cleared in the following:

Example

In the following UIBinder example we use YUI cssgrids for layouting, create a yui tabview with some mixed YUI and GWT buttons inside:We commented each YUI element introduced in the markup:

<ui:UiBinder xmlns:ui="urn:ui:com.google.gwt.uibinder"
 xmlns:g="urn:import:com.google.gwt.user.client.ui" xmlns:y="urn:import:org.sgx.yuigwt.ui">

<ui:style>
</ui:style>


<g:HTMLPanel>

 <!-- yui cssgrids -->
 <div class="yui3-g">
  <div class="yui3-u-5-24">
   <!-- yui button -->
   <button ui:field="yuiButton1" class="yui-button">the first YUI Button</button>

   <p>lak sjdlkaj slkdj alk sdlkaj slkdj lak sk djla sd</p>
   <p>lak sjdlkaj slkdj alk sdlkaj slkdj lak sk djla sd</p>

  </div>
  <div class="yui3-u-19-24">

   <!-- YUI tabview -->
   <div ui:field="tabView1" class="yui-tabview">
    <ul>
     <li>
      <a href="#foo">foo</a>
     </li>
     <li>
      <a href="#bar">bar</a>
     </li>
     <li>
      <a href="#baz">baz</a>
     </li>
    </ul>
    <div>
     <div id="foo">

      Some content with two buttons - one yui's and other GWT's<br />
      
      <!-- a YUI button -->
      <button ui:field="yuiButton2" class="yui-button">another yui button</button>
      
      <!-- a gwt button -->
      <g:Button ui:field="gwtButton2">..aGWTButton..</g:Button>

     </div>
     <div id="bar">
      a single GWT button:
      
      <g:Button text="GWT button1" ui:field="gwtButton1"></g:Button>
     </div>
     <div id="baz">baz content</div>
    </div>
   </div>

  </div>
 </div>

</g:HTMLPanel>
</ui:UiBinder>


Two important things to notice here:
  • For YUI Widgets we are writing using the same markup as expected and documented by YUI Widgets. For example, we give a plain html element <button> for creating a YUI Button, and give the markup documented in TabView Documentation - Minimal markup required.
  • We want to bind with GWT UIBinder the html elements corresponding to a YUI Widget, so we annotate them with ui:field="myfield".
  • Each html element corresponding to a YUI Widget must be annotated with an special class name corresponding to the aforementioned Widget. For example we annotate indicate it is a YUI Button using class="yui-button". This is how we indicate "this element must be rendered as a YUI Button"



And now the Java Sources corresponding to the UIBinder Composite definition I hope it is self documented:

package org.sgx.yuigwt.ui.test;

import org.sgx.yuigwt.ui.YUIBinder;
import org.sgx.yuigwt.ui.YUIBinderListener;
import org.sgx.yuigwt.yui.YuiContext;
import org.sgx.yuigwt.yui.event.EventCallback;
import org.sgx.yuigwt.yui.widget.button.Button;
import org.sgx.yuigwt.yui.widget.button.ButtonEvent;
import org.sgx.yuigwt.yui.widget.tabview.TabView;

import com.google.gwt.core.client.GWT;
import com.google.gwt.dom.client.Element;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.uibinder.client.UiBinder;
import com.google.gwt.uibinder.client.UiField;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.ui.Composite;
import com.google.gwt.user.client.ui.Widget;

/**
 * this is a common UIBinder Composite class. Notes:
 * 
 * < p>
 * 1) for YUI, we are binding plain HTML Elements, like @UiField Element
 * tabViewEl1;
 * < /p>
 * 
 * < p>
 * 2) then in the constructor, after this GWT widget is initialized with
 * initWidget(uiBinder.createAndBindUi(this));, we call YUIBinder.bindYUI
 * passing this Element UIFields corresponding to YUI stuff and register myself
 * as a listener to be notified when YUI binding is done to start working.
 * < /p>
 * 
 * < p>
 * 3) in yuiBinded() callback we ask for YUI Widgets and start working with
 * them.
 * < /p>
 * 
 * @author sg
 * 
 */
public class YUIInUiBinderTest2 extends Composite implements YUIBinderListener {

 interface MyUiBinder extends UiBinder< Widget, YUIInUiBinderTest2> {
 }

 private static MyUiBinder uiBinder = GWT.create(MyUiBinder.class);

 @UiField
 Element tabViewEl1;

 @UiField
 com.google.gwt.user.client.ui.Button gwtButton1, gwtButton2;

 @UiField
 Element yuiButtonEl1;

 @UiField
 Element yuiButtonEl2;

 private YUIBinder binderUtil;

 private Button yuiButton1;

 private TabView tabView;

 public YUIInUiBinderTest2(YuiContext y) {

  initWidget(uiBinder.createAndBindUi(this));

  binderUtil = new YUIBinder();

  /*
   * bind YUI stuff manually passing this Element UIFields corresponding
   * to YUI stuff and register myself as a listener to be notified when
   * YUI binding is done
   */

  binderUtil.bindYUI(y, this, new Element[] { tabViewEl1, yuiButtonEl1, yuiButtonEl2 }, this);

  /*
   * the gwt widgets can be used right away, but for using YUI widgets we
   * need to wait until binding is finished, see method yuiBindede() below
   */
  gwtButton2.addClickHandler(new ClickHandler() {
   @Override
   public void onClick(ClickEvent event) {
    Window.alert("gwtbutton1clicked");
    tabView.selectChild(2);
   }
  });
 }

 @Override
 public void yuiBinded() {
  /*
   * all YUI stuff is ready and rendered, we obtain the YUI widgets and
   * work directly in java:
   */
  yuiButton1 = binderUtil.getWidget(yuiButtonEl1).cast();
  tabView = binderUtil.getWidget(tabViewEl1).cast();

  yuiButton1.on("click", new EventCallback< ButtonEvent>() {
   @Override
   public void call(ButtonEvent e) {
    tabView.selectChild(1);
   }
  });
 }

}

Interesting stuff here:

  • Unlike GWT widgets, for work with YUI Widgets we will bind plain HTML Element (com.google.gwt.dom.client.Element).
  • We need to manually call our "YUIBinder", passing all the @UIField Elements correspondiing to YUI widgets and later, when the binding is dont, we can obtain the YUIGWT Widget classes to work with them in Java.

Known Issues

  • Some GWT Widgets are not designed to contain any HTML content only other GWT widets, so it is possiblt that including YUI Widgets there cannot behave well.
  • Putting a GWT Button inside a YUI TabView will make the GWT button to loose click handlers... ?

How this works and some decisions.

1 comentario:

Anónimo dijo...

Pretty component to content. I simply stumbled upon your site and in accession capital to claim that I acquire in fact loved account your weblog posts.
Any way I'll be subscribing in your augment and even I success you get right of entry to consistently fast.

Here is my website: garcinia cambogia walmart