diff --git a/lib/OpenLayers/Popup.js b/lib/OpenLayers/Popup.js index ecd2a1f61d..f844c3aae5 100644 --- a/lib/OpenLayers/Popup.js +++ b/lib/OpenLayers/Popup.js @@ -173,6 +173,20 @@ OpenLayers.Popup = OpenLayers.Class({ * Default is false. */ panMapIfOutOfView: false, + + /** + * APIProperty: keepInMap + * {Boolean} If panMapIfOutOfView is false, and this property is true, + * contrain the popup such that it always fits in the available map + * space. By default, this is not set on the base class. If you are + * creating popups that are near map edges and not allowing pannning, + * and especially if you have a popup which has a + * fixedRelativePosition, setting this to false may be a smart thing to + * do. Subclasses may want to override this setting. + * + * Default is false. + */ + keepInMap: false, /** * APIProperty: closeOnMove @@ -743,22 +757,44 @@ OpenLayers.Popup = OpenLayers.Class({ // is bigger than the map's viewport. // if (this.map && this.map.size) { - - // Note that there *was* a reference to a - // 'OpenLayers.Popup.SCROLL_BAR_WIDTH' constant here, with special - // tolerance for it and everything... but it was never defined in - // the first place, so I don't know what to think. + + var extraX = 0, extraY = 0; + if (this.keepInMap && !this.panMapIfOutOfView) { + var px = this.map.getPixelFromLonLat(this.lonlat); + switch (this.relativePosition) { + case "tr": + extraX = px.x; + extraY = this.map.size.h - px.y; + break; + case "tl": + extraX = this.map.size.w - px.x; + extraY = this.map.size.h - px.y; + break; + case "bl": + extraX = this.map.size.w - px.x; + extraY = px.y; + break; + case "br": + extraX = px.x; + extraY = px.y; + break; + default: + extraX = px.x; + extraY = this.map.size.h - px.y; + break; + } + } var maxY = this.map.size.h - this.map.paddingForPopups.top - this.map.paddingForPopups.bottom - - hPadding; - + hPadding - extraY; + var maxX = this.map.size.w - this.map.paddingForPopups.left - this.map.paddingForPopups.right - - wPadding; - + wPadding - extraX; + safeContentSize.w = Math.min(safeContentSize.w, maxX); safeContentSize.h = Math.min(safeContentSize.h, maxY); } diff --git a/lib/OpenLayers/Popup/Anchored.js b/lib/OpenLayers/Popup/Anchored.js index f8585beb80..c0cd89daca 100644 --- a/lib/OpenLayers/Popup/Anchored.js +++ b/lib/OpenLayers/Popup/Anchored.js @@ -21,6 +21,20 @@ OpenLayers.Popup.Anchored = * {String} Relative position of the popup ("br", "tr", "tl" or "bl"). */ relativePosition: null, + + /** + * APIProperty: keepInMap + * {Boolean} If panMapIfOutOfView is false, and this property is true, + * contrain the popup such that it always fits in the available map + * space. By default, this is set. If you are creating popups that are + * near map edges and not allowing pannning, and especially if you have + * a popup which has a fixedRelativePosition, setting this to false may + * be a smart thing to do. + * + * For anchored popups, default is true, since subclasses will + * usually want this functionality. + */ + keepInMap: true, /** * Parameter: anchor diff --git a/tests/Popup.html b/tests/Popup.html index f63e745b3e..f7f8384f66 100644 --- a/tests/Popup.html +++ b/tests/Popup.html @@ -86,6 +86,42 @@ t.ok(true, "update position doesn't fail when getLayerPxFromLonLat fails."); map.destroy(); } + function test_Popup_keepInMap(t) { + + var gb = OpenLayers.Util.getBrowserName; + OpenLayers.Util.getBrowserName = function() { return "mock"; } + t.plan(3); + var map = new OpenLayers.Map("map"); + map.addLayer(new OpenLayers.Layer("", {isBaseLayer: true})); + map.zoomToMaxExtent(); + var longString = "