summaryrefslogtreecommitdiffstats
path: root/client
diff options
context:
space:
mode:
authorAnna Koskinen <anna@vaadin.com>2015-02-25 13:43:39 +0200
committerVaadin Code Review <review@vaadin.com>2015-12-15 08:48:59 +0000
commitdace5ab66322c226b2cce79848a9c0518740f020 (patch)
treecad3d09ba45752b53b805b046fe2557b4bd9d05e /client
parentb7af23d8dc9529aaf7b80e417725a6d43dc69b7e (diff)
downloadvaadin-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.java80
-rw-r--r--client/src/com/vaadin/client/ui/VFilterSelect.java92
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();
- }
- }
}
/*