Help with dojo floating pane

10938
14
Jump to solution
08-29-2013 07:31 AM
BetsySchenck-Gardner
Occasional Contributor
I'm having an issue using dojox.layout.FloatingPane. I create the floating pane using the following code:
        // add popup floating pane          var dock = new dojox.layout.Dock({           id: 'dock', style: 'position:absolute; bottom:0; right:0; height:500px; width:0px; display:none; z-index:0;'         }, dojo.create('div', null, dojo.body()));         //find size of the map so to get the best possible initial size for the user         var popX = map.width;         var popY = map.height - 30;         pFloatingPane = new dojox.layout.FloatingPane({           title: "Download Menu",           resizable: true, //allow resizing           closable: false, //we never want to close a floating pane - this method destroys the dijit           dockable: true, // yes we want to dock it           dockTo: dock,           style: 'position:absolute;top:100px;right:10px;width:275px;height:375px;visibility:hidden;z-index:999 !important',           id: "pFloatingPane"         }, dojo.create('div', null, dojo.body()));         dojo.connect(pFloatingPane, 'onFocus', function () {           dijit.byId('pFloatingPane').bringToTop()         });         //do the same for onShow         dojo.connect(pFloatingPane, 'onShow', function () {           dijit.byId('pFloatingPane').bringToTop()         });         pFloatingPane.startup();

When you click on a button, the floating pane is made visible on the map.
       pFloatingPane.attr("content",downloadString);        pFloatingPane.show();

Everything works fine. The floating pane displays all the content it is suppose to. The problem I have is after I close the pane and then click on the button to open it again, its height increases. In fact it keeps increasing every single time you reopen the floating pane. Am I missing something that controls the size of the pane? I'm using the following stylesheets:
    <link rel="stylesheet" type="text/css" href="http://serverapi.arcgisonline.com/jsapi/arcgis/2.8/js/dojo/dojox/layout/resources/FloatingPane.css"/>     <link rel="stylesheet" type="text/css" href="http://serverapi.arcgisonline.com/jsapi/arcgis/2.8/js/dojo/dojox/layout/resources/ResizeHandle.css"/>        .dojoxFloatingPane {          padding: 0 0 20px 0 !important;          border: solid 1px #769DC0 !important;          font-family: Arial, "Kimberley", sans-serif;          font-size: 14px;       }        .dojoxFloatingPaneTitle {          border: none;          padding: 5px 0 10px 8px;          height: 16px;          background: #ABD6FF url('http://ajax.googleapis.com/ajax/libs/dojo/1.6/dijit/themes/claro/images/titlebar.png') repeat-x;       }        .dojoxFloatingPaneContent {          border-top: solid 1px #769DC0;          font-family: Arial, "Kimberley", sans-serif;          font-size: 12px;       }        .dojoxFloatingMinimizeIcon {          width: 15px;          height: 15px;          margin-right: 6px;          padding-right: 6px;          background: url('http://ajax.googleapis.com/ajax/libs/dojo/1.6/dijit/themes/claro/images/dialogCloseIcon.png') no-repeat 0 0;       }

Thanks for any assistance.
0 Kudos
1 Solution

Accepted Solutions
BenFousek
Occasional Contributor III
Betsy,
I know of the increased size on show phenomenon.  I don't understand it completely, but it's a layout issue with padding coupled with the floating pane's containerNode wanting to resize with padding on show. The critical part of the fix is padding:0 !important; in the .dojoxFloatingPane class.

First, here's a code update:
var mapinfofp = new dojox.layout.FloatingPane({   id: 'map-info-floating-pane',   title: 'Map Information',   resizable: false,   resizeAxis: null,   closable: false,   dockable: true,   dockTo: app.layout.dock,   style: 'position:absolute;top:90px;left:340px;width:270px;height:215px;visibility:hidden;overflow:hidden;',   href: 'html/map-info.html',   preload: false }, dojo.create('div', null, dojo.body())); mapinfofp.startup(); mapinfofp.on('focus', function () {   mapinfofp.bringToTop(); }); mapinfofp.on('show', function () {   mapinfofp.bringToTop(); });


Note the content wrapped in div with dojoxFloatingPaneWrapper class:
[HTML]
<div class="dojoxFloatingPaneWrapper">
<div data-dojo-type="mods/widget/MapInfo" data-dojo-props="map:app.map"></div>
</div>[/HTML]

The CSS:
/* floating pane */ .dojoxFloatingPaneWrapper {  padding:8px; } .dojoxFloatingPane {  padding:0 !important;  border:solid 1px #769DC0 !important; } .dojoxFloatingPaneTitle {  border: 1px solid #ffffff;  border-top: none;  background-color: #abd6ff;  background-image: url("http://ajax.googleapis.com/ajax/libs/dojo/1.9.1/dijit/themes/claro/images/standardGradient.png");  background-repeat: repeat-x;  background-image: -moz-linear-gradient(rgba(255, 255, 255, 0.7) 0%, rgba(255, 255, 255, 0) 100%);  background-image: -webkit-linear-gradient(rgba(255, 255, 255, 0.7) 0%, rgba(255, 255, 255, 0) 100%);  background-image: -o-linear-gradient(rgba(255, 255, 255, 0.7) 0%, rgba(255, 255, 255, 0) 100%);  background-image: linear-gradient(rgba(255, 255, 255, 0.7) 0%, rgba(255, 255, 255, 0) 100%);  _background-image: none;  padding: 5px 7px 4px 7px; } .dojoxFloatingPaneContent {  border-top:solid 1px #769DC0;  padding:0;  overflow:hidden } .dojoxFloatingMinimizeIcon {  /*custom minimize icon if desired*/ }

View solution in original post

14 Replies
BenFousek
Occasional Contributor III
Betsy,
I know of the increased size on show phenomenon.  I don't understand it completely, but it's a layout issue with padding coupled with the floating pane's containerNode wanting to resize with padding on show. The critical part of the fix is padding:0 !important; in the .dojoxFloatingPane class.

First, here's a code update:
var mapinfofp = new dojox.layout.FloatingPane({   id: 'map-info-floating-pane',   title: 'Map Information',   resizable: false,   resizeAxis: null,   closable: false,   dockable: true,   dockTo: app.layout.dock,   style: 'position:absolute;top:90px;left:340px;width:270px;height:215px;visibility:hidden;overflow:hidden;',   href: 'html/map-info.html',   preload: false }, dojo.create('div', null, dojo.body())); mapinfofp.startup(); mapinfofp.on('focus', function () {   mapinfofp.bringToTop(); }); mapinfofp.on('show', function () {   mapinfofp.bringToTop(); });


Note the content wrapped in div with dojoxFloatingPaneWrapper class:
[HTML]
<div class="dojoxFloatingPaneWrapper">
<div data-dojo-type="mods/widget/MapInfo" data-dojo-props="map:app.map"></div>
</div>[/HTML]

The CSS:
/* floating pane */ .dojoxFloatingPaneWrapper {  padding:8px; } .dojoxFloatingPane {  padding:0 !important;  border:solid 1px #769DC0 !important; } .dojoxFloatingPaneTitle {  border: 1px solid #ffffff;  border-top: none;  background-color: #abd6ff;  background-image: url("http://ajax.googleapis.com/ajax/libs/dojo/1.9.1/dijit/themes/claro/images/standardGradient.png");  background-repeat: repeat-x;  background-image: -moz-linear-gradient(rgba(255, 255, 255, 0.7) 0%, rgba(255, 255, 255, 0) 100%);  background-image: -webkit-linear-gradient(rgba(255, 255, 255, 0.7) 0%, rgba(255, 255, 255, 0) 100%);  background-image: -o-linear-gradient(rgba(255, 255, 255, 0.7) 0%, rgba(255, 255, 255, 0) 100%);  background-image: linear-gradient(rgba(255, 255, 255, 0.7) 0%, rgba(255, 255, 255, 0) 100%);  _background-image: none;  padding: 5px 7px 4px 7px; } .dojoxFloatingPaneContent {  border-top:solid 1px #769DC0;  padding:0;  overflow:hidden } .dojoxFloatingMinimizeIcon {  /*custom minimize icon if desired*/ }
JasonZou
Occasional Contributor III
The issue is a known issue recognized by the DOJO team. To my understanding, the cause is actually pretty simple. floatingPane.show will call resize method every time, which will increase its width and height by the floatingpane border width. What I did is to create a subclass of FloatingPane, and overwrite the resize method. Here is the code.

/**
 * resize the floating pane
 * @override The original one is buggy. That's why for the override.
 * 
 * @issue 
 * #1) Each time when the default resize() is called, the location of the floatingPane is 
 * changed to a new location with an offset added to its top and left.
 * 
 * #2) Each time when the default resize() is called, the size of the floatingPane is 
 * increased with a small amount in both width and height.
 *
 * @cause 
 * #1) The issue is caused by the below two commented out else-if statements, where 
 * if x/y is included in dim, the given new dimension, the left/top will be set to the x/y value. 
 * The problem is x/y is the absolute value related to the viewport or document root, while 
 * top/left is the offset value relative to the closest positioned ancestor, or its offsetParent. 
 * If the offsetParent is not the viewport or document root, the result will end up with top/left 
 * value increased with the x/y value of its offsetParent each time.
 *
 * #2) The issue is caused by the below two commented out dns.width/dns.height statements. 
 * Per the dojo source v1.8, dim is one of the two results based on startup(), show() and 
 * maxmimize(): the result of domGeom.position(this.domNode) and window.getBox(). The 
 * domGeom.position returns the width and height that include the border, but dns.width/dns.height 
 * does not. So set dns.width = dim.w actually increase the width by borderWidth * 2.
 * @solution 
 * #1)  top = dim.y - offsetParent.y; left = dim.x - offsetParent.x;
 * #2)  dns.width = dim.w - borderWidth * 2
 * 
 * @see http://bugs.dojotoolkit.org/ticket/5849
 * @see http://www.w3schools.com/jsref/dom_obj_all.asp
 * 
 * @comment
 * The above issue is with dojo 1.8 and below. Hopefully it can be fixed in the future release.
 * 
 */
resize: function(/* Object */dim){
 // override: do nothing if passing no dim.
 if (!dim) return;
 
 // summary:
 //  Size the FloatingPane and place accordingly
 dim = dim || this._naturalState;
 this._currentState = dim;
   
 // Variables used for the issue corrections

 // calculate the offset due to the border width
 // borderOffset = borderWidth * 2
 // @see http://www.w3schools.com/jsref/dom_obj_all.asp
 var borderOffset = this.domNode.offsetWidth - this.domNode.clientWidth;

 // get offsetParent node and its location values
 var offsetParent = this.domNode.offsetParent;
 var offsetLocation = {x: 0, y: 0};
 if (offsetParent) {
  var offsetParentLoc = domGeom.position(offsetParent);
  offsetLocation = {x: offsetParentLoc.x, y: offsetParentLoc.y};
 }

 // From the ResizeHandle we only get width and height information
 var dns = this.domNode.style;
 if("t" in dim){ dns.top = dim.t + "px"; }
//   else if("y" in dim){ dns.top = dim.y + "px"; }  // original line that causes issue #1. DON'T uncomment this line!!!
 else if("y" in dim){ dns.top = (dim.y - offsetLocation.y) + "px"; }  // correction of issue #1. 
 if("l" in dim){ dns.left = dim.l + "px"; }
//   else if("x" in dim){ dns.left = dim.x + "px"; }  // original line that causes issue #1. DON'T uncomment this line!!!
 else if("x" in dim){ dns.left = (dim.x - offsetLocation.x) + "px"; } // correction of issue #1.
//   dns.width = dim.w + "px";  // original line that causes the issue #2
//   dns.height = dim.h + "px";  // original line that causes the issue #2
 dns.width = (dim.w - borderOffset) + "px";  // correction of issue #2
 dns.height = (dim.h - borderOffset) + "px";  // correction of issue #2

 // Now resize canvas
 var mbCanvas = { l: 0, t: 0, w: (dim.w - borderOffset), h: (dim.h - this.focusNode.offsetHeight - borderOffset) };
 domGeom.setMarginBox(this.canvas, mbCanvas);

 // If the single child can resize, forward resize event to it so it can
 // fit itself properly into the content area
 this._checkIfSingleChild();
 if(this._singleChild && this._singleChild.resize){
  this._singleChild.resize(mbCanvas);
 }
}
0 Kudos
BetsySchenck-Gardner
Occasional Contributor
Jason,
Sorry for my stupidity but where would this resize function code be placed? In the main html page?
Betsy
0 Kudos
JasonZou
Occasional Contributor III
Create a module named as FloatingPane, and place it under some folder where other custom dijits saved, like myProject/dijits/.
In the main html page,
 <script>
  var dojoConfig = {
   parseOnLoad: false,
   async: true,
   packages: [{
    name: "dijits",
    location: "myProject/dijits"   // may need to revise it based on your project file structure
   }]
  };
 </script>
 <script src="http://js.arcgis.com/3.6/"></script>


Then in the code where you need to use the custom FloatingPane module, load it as
AMD:
define(["dijits/FloatingPane",...], function(FloatingPane, ...) {});

non-AMD:
dojo.require("dijits.FloatingPane");

Used in HTML:
<div data-dojo-type="dijits.FloatingPane" data-dojo-props="put floatingpane properties here"></div>

Used in JS:
var floatPane = new dijits.FloatingPane(...);

Here is the complete code of the custom FloatingPane.

/**
 * Base widget for all tool windows. Behave like the floating title pane with hide feature.
 * @class
 * @extends dojox/layout/FloatingPane
 * @features
 *   1. minimize to hide content area.
 *   2. click close button to hide instead of destroy.
 *   3. change the default close, minimize and restore icons.
 *   4. fixed the buggy resize function.
 */
define([
 "dojo/_base/declare",
 "dojo/_base/lang",
 "dojo/dom-construct",
 "dojo/dom-geometry",
 "dojo/dnd/move",
 "dojo/on",
 "dojox/layout/FloatingPane"
], function(declare, lang, domConstruct, domGeom, dndMove, on, FloatingPane){
 
 return declare(FloatingPane, {
  resize: function(/* Object */dim){
   // override: do nothing if passing no dim.
   if (!dim) return;
   
   // summary:
   //  Size the FloatingPane and place accordingly
   dim = dim || this._naturalState;
   this._currentState = dim;
   
   // Variables used for the issue corrections

   // calculate the offset due to the border width
   // borderOffset = borderWidth * 2
   // @see http://www.w3schools.com/jsref/dom_obj_all.asp
   var borderOffset = this.domNode.offsetWidth - this.domNode.clientWidth;

   // get offsetParent node and its location values
   var offsetParent = this.domNode.offsetParent;
   var offsetLocation = {x: 0, y: 0};
   if (offsetParent) {
    var offsetParentLoc = domGeom.position(offsetParent);
    offsetLocation = {x: offsetParentLoc.x, y: offsetParentLoc.y};
   }

   // From the ResizeHandle we only get width and height information
   var dns = this.domNode.style;
   if("t" in dim){ dns.top = dim.t + "px"; }
   else if("y" in dim){ dns.top = (dim.y - offsetLocation.y) + "px"; }  // correction of issue #1. 
   if("l" in dim){ dns.left = dim.l + "px"; }
   else if("x" in dim){ dns.left = (dim.x - offsetLocation.x) + "px"; } // correction of issue #1.
   dns.width = (dim.w - borderOffset) + "px";  // correction of issue #2
   dns.height = (dim.h - borderOffset) + "px";  // correction of issue #2

   // Now resize canvas
   var mbCanvas = { l: 0, t: 0, w: (dim.w - borderOffset), h: (dim.h - this.focusNode.offsetHeight - borderOffset) };
   domGeom.setMarginBox(this.canvas, mbCanvas);

   // If the single child can resize, forward resize event to it so it can
   // fit itself properly into the content area
   this._checkIfSingleChild();
   if(this._singleChild && this._singleChild.resize){
    this._singleChild.resize(mbCanvas);
   }
  },

  // override
  // Called when clicking the close button (X) located on the right side of the title bar.
  // The original implementation is to destroy the widget. It should hide instead.
  close: function() {
   this.hide();
  },
  
  // override
  // Enable the user to create custom onHide event handler
  hide: function() {
   this.inherited(arguments);
   this.onHide();
  },
  
  // event added
  onHide: function() {
   // stub method for event
  }
 });
});
BetsySchenck-Gardner
Occasional Contributor
Thanks to Ben and Jason for their help with this problem. In the end I used Ben's solution. It was the easier one to get working on my end but Jason's solution worked as well.
0 Kudos
AdrianMarsden
Occasional Contributor III
Ben - thanks for the answer - (and original code)  The only issue I have now is the vertical scroll bar obscures the resize handle (which is a user requirement) - this was what the 20 px padding in the original CSS brought to the party - so any ideas?

Cheers

ACM

Edit - so far I've managed to move it a bit with - seems OK.

.dojoxResizeHandle {


right:20px
}
0 Kudos
BenFousek
Occasional Contributor III
I've never used resizing or have scrolling. I size the floating pane to fit the content without overflow.

I was able to get a quick solution based on my example code above to be placed below the focus and show events.

dojo.connect(mapinfofp, 'resize', function() { dojo.style(mapinfofp.canvas, 'height', dojo.style(mapinfofp.canvas, 'height') - 18 + 'px') } );


18px seems to be enough.

The problem I see with this is always having the extra "padding" on the bottom even when no scroll bars are showing. I suppose you could check to see if the cavas node is scrolling before changing the height.

This is obviously non-AMD.
0 Kudos
AdrianMarsden
Occasional Contributor III
I've never used resizing or have scrolling. I size the floating pane to fit the content without overflow.

I was able to get a quick solution based on my example code above to be placed below the focus and show events.

dojo.connect(mapinfofp, 'resize', function() { dojo.style(mapinfofp.canvas, 'height', dojo.style(mapinfofp.canvas, 'height') - 18 + 'px') } );


18px seems to be enough.

The problem I see with this is always having the extra "padding" on the bottom even when no scroll bars are showing. I suppose you could check to see if the cavas node is scrolling before changing the height.

This is obviously non-AMD.


Cheers!

By the sounds of it, the appearance will match my CSS hack - leaves the padding there without scroll bars - but I think my users can cope - my floating pane contains the results of a "all layers, All features" ID task - just like old ArcIMS did, so it can have one feature in one table, or 100+ in several tables.
0 Kudos
BenFousek
Occasional Contributor III
Cheers!


Back when I first started using floating panes I had the same issues with the resizer and resizing. The solution at the time was static dimensions. Grids and custom mods with complex layout and lots of resizing were particularly difficult to work with in a floating pane. I never went back and just created closeable tabs for a tab container for those sorts of things. At any rate, you've inspired me to revisit floating panes while going to AMD. I can think of several items I'd like to get into a floating pane.

Cheers and good luck to you!
0 Kudos