GWT 2.2.0 автоматическое скрытие всплывающей панели при касании событий

#gwt #touch #mobile-safari

#gwt #коснитесь #mobile-safari

Вопрос:

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

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

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

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

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

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

 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’ — это всплывающая панель, которую я пытаюсь закрыть при внешних событиях касания.
Печально, что это работает при нажатии мыши при тестировании в любом другом браузере на Земле, но не на iPad.

Еще одна вещь, которую я попробовал, — это добавить TouchStartHandler в стекло всплывающей панели (серая штука за ней). Я надеялся, что смогу таким образом перехватывать события касания, но мне не удалось запустить события в glass, поскольку он каким-то забавным образом привязан к 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:

Здесь недостаточно пользователей 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
         );
    }-*/;


}