GWT 2.2.0 PopupPanel autoHide для событий TOUCH - PullRequest
3 голосов
/ 07 апреля 2011

PopupPanel - это класс в GWT, написанный (ахем) давным-давно (именно поэтому он так отстой), который позволяет показывать всплывающие окна с контентом.Одним из параметров является autoHide, где, если есть определенное событие вне всплывающего окна, оно закрывает всплывающее окно.Он хорошо работает на всем, кроме сафари Mobil (SM).Причина в том, что SM не запускает события щелчка при касании.Он запускает сенсорные события.PopupPanel жестко запрограммирован для поиска ClickEvents.

В частности, код говорит:

case Event.ONMOUSEDOWN:
   ...
   if (!eventTargetsPopupOrPartner && autoHide) {
      hide(true);
   ...

Очевидно, что это не завершено, и он также должен включать Event.ONTOUCHSTART

Проблема в том, что все методы и поля являются частными, поэтому я не могу добавить эту функцию.Это большая болтовня со стороны команды GWT, но на самом деле это не проблема, поскольку я мог просто создать свой собственный класс и скопировать содержимое PopupPanel.Большая проблема заключается в том, что nativeEventPreview не записывает события Touch!

Я попытался добавить следующее в предварительный просмотр событий:

private static NativePreviewHandler nativePreviewHandler = new NativePreviewHandler() {
    public void onPreviewNativeEvent(NativePreviewEvent event) {
        Event nativeEvent = Event.as(event.getNativeEvent());
        switch (nativeEvent.getTypeInt()) {         
        case Event.ONTOUCHSTART:        
        case Event.ONMOUSEDOWN:
            EventTarget target = nativeEvent.getEventTarget();
            if (!Element.is(target) || !popup.getElement().isOrHasChild(Element.as(target))) {                  
                popup.hide();
            } break;
        }       
            }
};

Где popup - это PopupPanel, которую я пытаюсьчтобы закрыть на внешних событиях касания.Грустная вещь, это работает для мыши вниз при тестировании в любом другом браузере на Земле, но не на iPad.

Еще одна вещь, которую я попробовал, это добавление TouchStartHandler к стеклу PopupPanel (серый цвет за ним),Я боролся с надеждой, что смогу уловить события касания таким образом, но я не смог заставить события срабатывать на стекле, так как он каким-то забавным образом привязан к DOM.Мой код:

private static class ProperPopupPanel extends PopupPanel {

    public ProperPopupPanel() {
        super();            
}          

    void setHideOnGlassTouch() {
        setGlassEnabled(true);

        TouchableLabeThatDoesntCrashOnWrap glass = new TouchableLabeThatDoesntCrashOnWrap(getGlassElement());
        glass.addTouchStartHandler(new TouchStartHandler() {

            @Override
            public void onTouchStart(TouchStartEvent event) {                   
                hide();                 
            }

        });
        glass.addClickHandler(new ClickHandler() {

            @Override
            public void onClick(ClickEvent event) {
                hide();                     
            }               
        });
    }       

    private class TouchableLabeThatDoesntCrashOnWrap extends Label {
        public TouchableLabeThatDoesntCrashOnWrap(Element element) {
            super(element);
            super.onAttach();
        }
    }
}

На мой взгляд, это должно работать, но это не так.Я не знаю почему.Любые идеи или предложения приветствуются.Благодаря.

1 Ответ

7 голосов
/ 08 апреля 2011

Недостаточно пользователей GWT здесь ... ну, я создал свой собственный класс, который добавляет сенсорные обработчики через JSNI ...

/**
 * Overwrite of the usual PopupPanel with a modification that this one
 * works well on touch-enabled browsers.
 * @author McTrafik
 */
public class ProperPopupPanel extends PopupPanel {

    ////////////////////////////////////////////////////////////
    /////////// OVERRIDES //////////////////////////////////////
    ////////////////////////////////////////////////////////////

    public ProperPopupPanel() {
        super();
        setTouchListener();
    }

    @Override
    public void hide() {
        super.hide();
        removeTouchListener();

    }

    @Override
    public void show() {
        super.show();
        addTouchListener();
    }

    ////////////////////////////////////////////////////////////
    /////////// NANDLERS ///////////////////////////////////////
    ////////////////////////////////////////////////////////////

    protected JavaScriptObject touchHandler;

    /**
     * Handle a touch event that happened while the popup is open.
     * @param event - The event to handle
     */
    protected void handleTouchEvent(Event event) {
        // Check to see if the events should be firing in the first place.
        if (!isShowing()) {
            removeTouchListener();
            return;
        }
        // Check if the event happened within the popup
        EventTarget target = event.getEventTarget();
        if (!Element.is(target) || !getElement().isOrHasChild(Element.as(target))) {
            // Stop event if the popup is modal
            if (isModal()) event.preventDefault();
            // Close the popup if the event happened outside
            if (isAutoHideEnabled()) {
                hide(true);
                removeTouchListener();
            }
        }
    };


    /**
     * Create a touchHandler that knows how to point to this instance.
     * Without it there's a cast exception that happens.
     */
    protected native void setTouchListener() /*-{
        var caller = this;
        this.@[package].ProperPopupPanel::touchHandler = function(event) {
            caller.@[package].ProperPopupPanel::handleTouchEvent(Lcom/google/gwt/user/client/Event;)(event);
        }
    }-*/;


    /**
     * Add a touch listener that will listen to touch events.
     */
    protected native void addTouchListener() /*-{
        $doc.addEventListener(
            "touchstart", 
            this.@[package].ProperPopupPanel::touchHandler, 
            true
        );
        $doc.addEventListener(
            "MozTouchDown", 
            this.@[package].ProperPopupPanel::touchHandler, 
            true
        ); 
    }-*/;


    /**
     * Remove the touch listeners
     */
    protected native void removeTouchListener() /*-{
         $doc.removeEventListener(
             "touchstart", 
             this.@[package].ProperPopupPanel::touchHandler, 
             true
         );
         $doc.removeEventListener(
             "MozTouchDown",
             this.@[package].ProperPopupPanel::touchHandler, 
             true
         );
    }-*/;


}
...