GWT, iFrame e supporto evento onLoad su Internet Explorer

Google Web Toolkit, Java Library & Framework, Java World 0 1

Google Web ToolkitL’elemento <iFrame/> su Internet Explorer non supporta l’evento onLoad, che può essere utile nel caso ci volessimo registrare su tale evento per fare una certa cosa al termine del caricamento del contenuto dell’iframe stesso (ad esempio fare sparire un layer con una scritta di “caricamento in corso”).

GWT prevede un widget che fa da wrapper proprio all’elemento <iFrame/> che è com.google.gwt.user.client.ui.Frame.

Per risolvere il problema ci appoggiamo ad un evento base che Internet Explorer invece gestisce sul <iFrame/>, e cioè “readystatechange“, che ci permette di intercettare anche l’evento di “documento caricato” (readyState == “complete”).

Per fare ciò è necessario usare JSNI (javascript native interface) di GWT, simile a JNI (java native interface) di java, che ci permette di scrivere del codice nativo (javascript in questo caso) che verrà interpretato direttamente dal browser.

Ovviamente il nostro widget deve supportare l’evento anche sugli altri browser, per garantire la portabilità della nostra applicazione. Per far ciò viene anche intercettato l’evento BrowserEvent già previsto nel widget base, che funziona sugli altri browser.

Il codice seguente ci fa vedere come scrivere il nostro widget MyFrame a partire da quello base GWT.

package com.example.mywidgets;

import com.google.gwt.core.client.GWT;
import com.google.gwt.dom.client.IFrameElement;
import com.google.gwt.event.shared.HandlerRegistration;
import com.google.gwt.user.client.Event;
import com.google.gwt.user.client.ui.Frame;
import com.example.myevents.IFrameLoadEvent;
import com.example.myevents.IFrameLoadHandler;

/**
 *
 * @author S.DiLoro
 * Estensione custom del Frame GWT (iFrame) che supporta la registrazione
 * all'evento di &quot;contenuto caricato&quot; all'interno dell'iFrame, con una gestione
 * particolare per InternetExplorer, che non supporta nativamente l'evento di &quot;onLoad&quot;
 */
public class MyFrame extends Frame {

    public MyFrame() {
        super();
        final IFrameElement iframe = IFrameElement.as(getElement());
        sinkEvents(Event.ONLOAD);

        // only for Internet Explorer
        registerOnReadyStateChange(iframe);
    }

    public MyFrame(String url) {
        super(url);
        final IFrameElement iframe = IFrameElement.as(getElement());
        sinkEvents(Event.ONLOAD);

        // only for Internet Explorer
        registerOnReadyStateChange(iframe);
    }

    @Override
    public void setUrl(String url) {
        super.setUrl(url);
    }

    @Override
    public void onBrowserEvent(Event event) {
        super.onBrowserEvent(event);
        if (event.getTypeInt() == Event.ONLOAD) {
            fireLoadEvent();
        }
    }

    void fireLoadEvent() {
        GWT.log(&quot;LoadEvent fired&quot;, null);
        fireEvent(
            new IFrameLoadEvent()
        );
    }

    // solo per Internet Explorer
    public native void registerOnReadyStateChange(IFrameElement iframe)/*-{
        var that = this;
        iframe.onreadystatechange = function(){
            if (document.readyState == &quot;complete&quot;){
                that.@com.example.mywidgets.MyFrame::fireLoadEvent()();
            }
        };
    }-*/;

    public HandlerRegistration addIFrameLoadHandler(IFrameLoadHandler handler) {
        return addHandler(handler, IFrameLoadEvent.TYPE);
    }
}

Come è possibile notare, per la gestione dell’evento ci si è appoggiati all’infrastruttura standard di GWT, che prevede la creazione di un Handler e un Event custom, con la possibilità di lanciare l’evento attraverso il metodo fireEvent(event) che viene ereditato da com.google.gwt.user.client.ui.UIObject, oggetto che sta nella catena di ereditarietà dell’oggetto Frame.

Sulla nostra classe aggiungiamo infine il metodo addIFrameLoadHandler che permette al client del nostro nuovo widget di registrare un handler sull’evento IFrameLoadEvent.

L’Handler e l’Event sono rispettivamente l’interfaccia IFrameLoadHandler e l’oggetto IFrameLoadEvent.

Di seguito il codice dell’interfaccia IFrameLoadHandler:

package com.example.myevents;

import com.google.gwt.event.shared.EventHandler;

public interface IFrameLoadHandler extends EventHandler {

    void onIFrameLoad(IFrameLoadEvent event);
}

Il codice dell’oggetto IFrameLoadEvent:

package com.example.myevents;

import com.google.gwt.event.shared.GwtEvent;
import com.google.gwt.event.shared.GwtEvent.Type;

/**
 *
 * @author S.DiLoro
 */
public class IFrameLoadEvent extends GwtEvent&lt;IFrameLoadHandler&gt; {

    public IFrameLoadEvent() {
        super();
    }

    public static final Type&lt;IFrameLoadHandler&gt; TYPE = new Type&lt;IFrameLoadHandler&gt;();

    @Override
    protected void dispatch(IFrameLoadHandler handler) {
        handler.onIFrameLoad(this);
    }

    @Override
    public com.google.gwt.event.shared.GwtEvent.Type&lt;IFrameLoadHandler&gt; getAssociatedType() {
        return TYPE;
    }
}

Per finire un esempio di codice che usa il nostro nuovo widget:

MyFrame f = new MyFrame();
f.addIFrameLoadHandler(new IFrameLoadHandler() {
    @Override
        public void onIFrameLoad(IFrameLoadEvent event) {
        //di seguito possiamo mettere il nostro codice da esegure a fronte del verificarsi dell'evento
        }
    }
);

About the author / 

Salvatore Di Loro

Related Posts

Leave a reply

Your email address will not be published. Required fields are marked *

Twitter @sdiloro

Instagram

Flickr