diff --git a/lib/OpenLayers/Handler/MouseWheel.js b/lib/OpenLayers/Handler/MouseWheel.js index 060022a7ec..86bfef3707 100644 --- a/lib/OpenLayers/Handler/MouseWheel.js +++ b/lib/OpenLayers/Handler/MouseWheel.js @@ -66,61 +66,128 @@ OpenLayers.Handler.MouseWheel = OpenLayers.Class(OpenLayers.Handler, { * e - {Event} */ onWheelEvent: function(e){ - // first check keyboard modifiers - if (!this.checkModifiers(e)) { + + // make sure we have a map and check keyboard modifiers + if (!this.map || !this.checkModifiers(e)) { return; } - // first determine whether or not the wheeling was inside the map - var inMap = false; + + // Ride up the element's DOM hierarchy to determine if it or any of + // its ancestors was: + // * specifically marked as scrollable + // * one of our layer divs + // * the map div + // + var overScrollableDiv = false; + var overLayerDiv = false; + var overMapDiv = false; + var elem = OpenLayers.Event.element(e); - while(elem != null) { - if (this.map && elem == this.map.div) { - inMap = true; - break; + while((elem != null) && !overMapDiv && !overScrollableDiv) { + + if (!overScrollableDiv) { + try { + if (elem.currentStyle) { + overflow = elem.currentStyle["overflow"]; + } else { + var style = + document.defaultView.getComputedStyle(elem, null); + var overflow = style.getPropertyValue("overflow"); + } + overScrollableDiv = ( overflow && + (overflow == "auto") || (overflow == "scroll") ); + } catch(err) { + //sometimes when scrolling in a popup, this causes + // obscure browser error + } } + + if (!overLayerDiv) { + for(var i=0; i < this.map.layers.length; i++) { + if (elem == this.map.layers[i].div) { + overLayerDiv = true; + break; + } + } + } + overMapDiv = (elem == this.map.div); + elem = elem.parentNode; } - if (inMap) { - var delta = 0; - if (!e) { - e = window.event; + // Logic below is the following: + // + // If we are over a scrollable div or not over the map div: + // * do nothing (let the browser handle scrolling) + // + // otherwise + // + // If we are over the layer div: + // * zoom/in out + // then + // * kill event (so as not to also scroll the page after zooming) + // + // otherwise + // + // Kill the event (dont scroll the page if we wheel over the + // layerswitcher or the pan/zoom control) + // + if (!overScrollableDiv && overMapDiv) { + if (overLayerDiv) { + this.wheelZoom(e); } - if (e.wheelDelta) { - delta = e.wheelDelta/120; - if (window.opera && window.opera.version() < 9.2) { - delta = -delta; - } - } else if (e.detail) { - delta = -e.detail / 3; - } - if (delta) { - // add the mouse position to the event because mozilla has a bug - // with clientX and clientY (see https://bugzilla.mozilla.org/show_bug.cgi?id=352179) - // getLonLatFromViewPortPx(e) returns wrong values - if (this.mousePosition) { - e.xy = this.mousePosition; - } - if (!e.xy) { - // If the mouse hasn't moved over the map yet, then - // we don't have a mouse position (in FF), so we just - // act as if the mouse was at the center of the map. - // Note that we can tell we are in the map -- and - // this.map is ensured to be true above. - e.xy = this.map.getPixelFromLonLat(this.map.getCenter()); - } - if (delta < 0) { - this.callback("down", [e, delta]); - } else { - this.callback("up", [e, delta]); - } - } - - //only wheel the map, not the window OpenLayers.Event.stop(e); } }, + /** + * Method: wheelZoom + * Given the wheel event, we carry out the appropriate zooming in or out, + * based on the 'wheelDelta' or 'detail' property of the event. + * + * Parameters: + * e - {Event} + */ + wheelZoom: function(e) { + + var delta = 0; + if (!e) { + e = window.event; + } + if (e.wheelDelta) { + delta = e.wheelDelta/120; + if (window.opera && window.opera.version() < 9.2) { + delta = -delta; + } + } else if (e.detail) { + delta = -e.detail / 3; + } + if (delta) { + // add the mouse position to the event because mozilla has + // a bug with clientX and clientY (see + // https://bugzilla.mozilla.org/show_bug.cgi?id=352179) + // getLonLatFromViewPortPx(e) returns wrong values + if (this.mousePosition) { + e.xy = this.mousePosition; + } + if (!e.xy) { + // If the mouse hasn't moved over the map yet, then + // we don't have a mouse position (in FF), so we just + // act as if the mouse was at the center of the map. + // Note that we can tell we are in the map -- and + // this.map is ensured to be true above. + e.xy = this.map.getPixelFromLonLat( + this.map.getCenter() + ); + } + if (delta < 0) { + this.callback("down", [e, delta]); + } else { + this.callback("up", [e, delta]); + } + } + }, + /** * Method: mousemove * Update the stored mousePosition on every move. diff --git a/tests/Handler/test_MouseWheel.html b/tests/Handler/test_MouseWheel.html index 55110da60d..f5b4933f3a 100644 --- a/tests/Handler/test_MouseWheel.html +++ b/tests/Handler/test_MouseWheel.html @@ -57,7 +57,7 @@ handler.activate(); var delta = 120; if (window.opera && window.opera.version() < 9.2) delta = -delta; - handler.onWheelEvent({'target':map.div, wheelDelta: delta}); + handler.onWheelEvent({'target':map.layers[0].div, wheelDelta: delta}); t.ok(pass, "evt.xy was set even without a mouse move"); }