diff options
author | Anna Koskinen <anna@vaadin.com> | 2015-02-25 13:43:39 +0200 |
---|---|---|
committer | Vaadin Code Review <review@vaadin.com> | 2015-12-15 08:48:59 +0000 |
commit | dace5ab66322c226b2cce79848a9c0518740f020 (patch) | |
tree | cad3d09ba45752b53b805b046fe2557b4bd9d05e /client | |
parent | b7af23d8dc9529aaf7b80e417725a6d43dc69b7e (diff) | |
download | vaadin-framework-dace5ab66322c226b2cce79848a9c0518740f020.tar.gz vaadin-framework-dace5ab66322c226b2cce79848a9c0518740f020.zip |
Fix mouse wheel scrolling of ComboBox in IE11 (#16918)
IE11 is broken so that the simple implementation always moves up on any
mouse wheel event. Therefore, this change borrows the approach taken by
Escalator for low-level handling of mouse wheel events in a way compatible
with all supported browsers.
Change-Id: I98c89d3ccfeea38d6a454ef708f0eb7d1d3f480c
Diffstat (limited to 'client')
-rw-r--r-- | client/src/com/vaadin/client/ui/JsniMousewheelHandler.java | 80 | ||||
-rw-r--r-- | client/src/com/vaadin/client/ui/VFilterSelect.java | 92 |
2 files changed, 154 insertions, 18 deletions
diff --git a/client/src/com/vaadin/client/ui/JsniMousewheelHandler.java b/client/src/com/vaadin/client/ui/JsniMousewheelHandler.java new file mode 100644 index 0000000000..82ea768871 --- /dev/null +++ b/client/src/com/vaadin/client/ui/JsniMousewheelHandler.java @@ -0,0 +1,80 @@ +/* + * Copyright 2000-2014 Vaadin Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.vaadin.client.ui; + +import com.google.gwt.core.client.JavaScriptObject; +import com.google.gwt.dom.client.Element; +import com.google.gwt.user.client.Event; +import com.google.gwt.user.client.ui.Widget; +import com.vaadin.client.widgets.Escalator; + +/** + * A mousewheel handling class to get around the limits of + * {@link Event#ONMOUSEWHEEL}. + * + * For internal use only. May be removed or replaced in the future. + * + * @see Escalator.JsniWorkaround + */ +abstract class JsniMousewheelHandler { + + /** + * A JavaScript function that handles the mousewheel DOM event, and passes + * it on to Java code. + * + * @see #createMousewheelListenerFunction(Widget) + */ + protected final JavaScriptObject mousewheelListenerFunction; + + protected JsniMousewheelHandler(final Widget widget) { + mousewheelListenerFunction = createMousewheelListenerFunction(widget); + } + + /** + * A method that constructs the JavaScript function that will be stored into + * {@link #mousewheelListenerFunction}. + * + * @param widget + * a reference to the current instance of {@link Widget} + */ + protected abstract JavaScriptObject createMousewheelListenerFunction( + Widget widget); + + public native void attachMousewheelListener(Element element) + /*-{ + if (element.addEventListener) { + // FireFox likes "wheel", while others use "mousewheel" + var eventName = 'onmousewheel' in element ? 'mousewheel' : 'wheel'; + element.addEventListener(eventName, this.@com.vaadin.client.ui.JsniMousewheelHandler::mousewheelListenerFunction); + } else { + // IE8 + element.attachEvent("onmousewheel", this.@com.vaadin.client.ui.JsniMousewheelHandler::mousewheelListenerFunction); + } + }-*/; + + public native void detachMousewheelListener(Element element) + /*-{ + if (element.addEventListener) { + // FireFox likes "wheel", while others use "mousewheel" + var eventName = element.onwheel===undefined?"mousewheel":"wheel"; + element.removeEventListener(eventName, this.@com.vaadin.client.ui.JsniMousewheelHandler::mousewheelListenerFunction); + } else { + // IE8 + element.detachEvent("onmousewheel", this.@com.vaadin.client.ui.JsniMousewheelHandler::mousewheelListenerFunction); + } + }-*/; + +} diff --git a/client/src/com/vaadin/client/ui/VFilterSelect.java b/client/src/com/vaadin/client/ui/VFilterSelect.java index 6ddce3d93c..99ebde1910 100644 --- a/client/src/com/vaadin/client/ui/VFilterSelect.java +++ b/client/src/com/vaadin/client/ui/VFilterSelect.java @@ -25,9 +25,11 @@ import java.util.List; import java.util.Set; import com.google.gwt.aria.client.Roles; +import com.google.gwt.core.client.JavaScriptObject; import com.google.gwt.core.client.Scheduler; import com.google.gwt.core.client.Scheduler.ScheduledCommand; import com.google.gwt.dom.client.Element; +import com.google.gwt.dom.client.NativeEvent; import com.google.gwt.dom.client.Style; import com.google.gwt.dom.client.Style.Display; import com.google.gwt.dom.client.Style.Unit; @@ -219,6 +221,50 @@ public class VFilterSelect extends Composite implements Field, KeyDownHandler, } } + /** An inner class that handles all logic related to mouse wheel. */ + private class MouseWheeler extends JsniMousewheelHandler { + + public MouseWheeler() { + super(VFilterSelect.this); + } + + @Override + protected native JavaScriptObject createMousewheelListenerFunction( + Widget widget) + /*-{ + return $entry(function(e) { + var deltaX = e.deltaX ? e.deltaX : -0.5*e.wheelDeltaX; + var deltaY = e.deltaY ? e.deltaY : -0.5*e.wheelDeltaY; + + // IE8 has only delta y + if (isNaN(deltaY)) { + deltaY = -0.5*e.wheelDelta; + } + + @com.vaadin.client.ui.VFilterSelect.JsniUtil::moveScrollFromEvent(*)(widget, deltaX, deltaY, e); + }); + }-*/; + + } + + /** + * A utility class that contains utility methods that are usually called + * from JSNI. + * <p> + * The methods are moved in this class to minimize the amount of JSNI code + * as much as feasible. + */ + static class JsniUtil { + public static void moveScrollFromEvent(final Widget widget, + final double deltaX, final double deltaY, + final NativeEvent event) { + + if (!Double.isNaN(deltaY)) { + ((VFilterSelect) widget).suggestionPopup.scroll(deltaY); + } + } + } + /** * Represents the popup box with the selection options. Wraps a suggestion * menu. @@ -243,6 +289,8 @@ public class VFilterSelect extends Composite implements Field, KeyDownHandler, private int topPosition; + private final MouseWheeler mouseWheeler = new MouseWheeler(); + /** * Default constructor */ @@ -275,6 +323,18 @@ public class VFilterSelect extends Composite implements Field, KeyDownHandler, setPreviewingAllNativeEvents(true); } + @Override + protected void onLoad() { + super.onLoad(); + mouseWheeler.attachMousewheelListener(getElement()); + } + + @Override + protected void onUnload() { + mouseWheeler.detachMousewheelListener(getElement()); + super.onUnload(); + } + /** * Shows the popup where the user can see the filtered options * @@ -531,6 +591,20 @@ public class VFilterSelect extends Composite implements Field, KeyDownHandler, } } + private void scroll(double deltaY) { + boolean scrollActive = menu.isScrollActive(); + + debug("VFS.SP: scroll() scrollActive: " + scrollActive); + + if (!scrollActive) { + if (deltaY > 0d) { + lazyPageScroller.scrollDown(); + } else { + lazyPageScroller.scrollUp(); + } + } + } + @Override public void onBrowserEvent(Event event) { debug("VFS.SP: onBrowserEvent()"); @@ -543,24 +617,6 @@ public class VFilterSelect extends Composite implements Field, KeyDownHandler, lazyPageScroller.scrollDown(); } - } else if (event.getTypeInt() == Event.ONMOUSEWHEEL) { - - boolean scrollNotActive = !menu.isScrollActive(); - - debug("VFS.SP: onBrowserEvent() scrollNotActive: " - + scrollNotActive); - - if (scrollNotActive) { - int velocity = event.getMouseWheelVelocityY(); - - debug("VFS.SP: onBrowserEvent() velocity: " + velocity); - - if (velocity > 0) { - lazyPageScroller.scrollDown(); - } else { - lazyPageScroller.scrollUp(); - } - } } /* |