kristian.kuhn
8 Jan 2010, 10:34 AM
In Ext 3.1 the floating menu's are not sizing properly when the document height is larger than the view height when you right click at the bottom on the view. They are sized very small and cannot be used. Secondly the sizing algorithm for fitting a floating menu into a view space smaller than the menu's full height sizes the menu extremely small and unusable. In addition the algorithm for calculating the max available height for the menu does not account for scroll position of the document body causing unusual behavior described below.
The problems are in the constrainScroll method on Menu. I have modified that method to resolve these issues.
1. The y coordinate needs to be normalized to account for the scrollTop offset so that we are all playing in the same coordinate space. If you don't do this max can become negative when the position y coordinate is larger than the height of the view.
var pe = Ext.fly(this.el.dom.parentNode);
var st = pe.getScroll().top;
var vh = pe.getViewSize().height;
//Normalize y by the scroll position for the parent element. Need to move it into the coordinate space
//of the view.
var norm_y = y - st;
max = this.maxHeight ? this.maxHeight : vh - norm_y;2. The max value and y coordinate are adjusted to best fit and size the menu into the available space. First we check to see if full is larger than the view height(vh). If it is we set max to vh so that the menu will get as big as possible and adjust the y position. Secondly if full is less than vh we can fit the menu in the view space we just need to adjust the y position so that the menu fits.
if(full > vh) {
max = vh;
//Set new_y equal to (0,0) in view space by reducing y by the value of norm_y
new_y = y - norm_y;
} else if(max < full) {
new_y = y - (full - max);
max = full;
} 3. Finally we return the adjusted y position which is used to overwrite the previous y position in the showAt method on Menu.
Snippet from showAt
if(this.enableScrolling){
// set the position so we can figure out the constrain value.
this.el.setXY(xy);
//CS: override y to push the point up to fit the menu if
//there is enough space above the point
xy[1] = this.constrainScroll(xy[1]);
xy = [this.el.adjustForConstraints(xy)[0], xy[1]];
}else{
//constrain to the viewport.
xy = this.el.adjustForConstraints(xy);
}The complete code for constrainScroll is below. We were hoping this could be incorporated into the baseline or if this is not the best solution a similar solution could be incorporated.
constrainScroll : function(y){
var max, full = this.ul.setHeight('auto').getHeight();
var new_y = y;
if(this.floating){
var pe = Ext.fly(this.el.dom.parentNode);
var st = pe.getScroll().top;
var vh = pe.getViewSize().height;
//Normalize y by the scroll position for the parent element. Need to move it into the coordinate space
//of the view.
var norm_y = y - st;
max = this.maxHeight ? this.maxHeight : vh - norm_y;
if(full > vh) {
max = vh;
//Set new_y equal to (0,0) in view space by reducing y by the value of norm_y
new_y = y - norm_y;
} else if(max < full) {
new_y = y - (full - max);
max = full;
}
}else{
max = this.getHeight();
}
if(full > max && max > 0){
this.activeMax = max - this.scrollerHeight * 2 - this.el.getFrameWidth('tb') - Ext.num(this.el.shadowOffset, 0);
this.ul.setHeight(this.activeMax);
this.createScrollers();
this.el.select('.x-menu-scroller').setDisplayed('');
}else{
this.ul.setHeight(full);
this.el.select('.x-menu-scroller').setDisplayed('none');
}
this.ul.dom.scrollTop = 0;
return new_y;
}
The problems are in the constrainScroll method on Menu. I have modified that method to resolve these issues.
1. The y coordinate needs to be normalized to account for the scrollTop offset so that we are all playing in the same coordinate space. If you don't do this max can become negative when the position y coordinate is larger than the height of the view.
var pe = Ext.fly(this.el.dom.parentNode);
var st = pe.getScroll().top;
var vh = pe.getViewSize().height;
//Normalize y by the scroll position for the parent element. Need to move it into the coordinate space
//of the view.
var norm_y = y - st;
max = this.maxHeight ? this.maxHeight : vh - norm_y;2. The max value and y coordinate are adjusted to best fit and size the menu into the available space. First we check to see if full is larger than the view height(vh). If it is we set max to vh so that the menu will get as big as possible and adjust the y position. Secondly if full is less than vh we can fit the menu in the view space we just need to adjust the y position so that the menu fits.
if(full > vh) {
max = vh;
//Set new_y equal to (0,0) in view space by reducing y by the value of norm_y
new_y = y - norm_y;
} else if(max < full) {
new_y = y - (full - max);
max = full;
} 3. Finally we return the adjusted y position which is used to overwrite the previous y position in the showAt method on Menu.
Snippet from showAt
if(this.enableScrolling){
// set the position so we can figure out the constrain value.
this.el.setXY(xy);
//CS: override y to push the point up to fit the menu if
//there is enough space above the point
xy[1] = this.constrainScroll(xy[1]);
xy = [this.el.adjustForConstraints(xy)[0], xy[1]];
}else{
//constrain to the viewport.
xy = this.el.adjustForConstraints(xy);
}The complete code for constrainScroll is below. We were hoping this could be incorporated into the baseline or if this is not the best solution a similar solution could be incorporated.
constrainScroll : function(y){
var max, full = this.ul.setHeight('auto').getHeight();
var new_y = y;
if(this.floating){
var pe = Ext.fly(this.el.dom.parentNode);
var st = pe.getScroll().top;
var vh = pe.getViewSize().height;
//Normalize y by the scroll position for the parent element. Need to move it into the coordinate space
//of the view.
var norm_y = y - st;
max = this.maxHeight ? this.maxHeight : vh - norm_y;
if(full > vh) {
max = vh;
//Set new_y equal to (0,0) in view space by reducing y by the value of norm_y
new_y = y - norm_y;
} else if(max < full) {
new_y = y - (full - max);
max = full;
}
}else{
max = this.getHeight();
}
if(full > max && max > 0){
this.activeMax = max - this.scrollerHeight * 2 - this.el.getFrameWidth('tb') - Ext.num(this.el.shadowOffset, 0);
this.ul.setHeight(this.activeMax);
this.createScrollers();
this.el.select('.x-menu-scroller').setDisplayed('');
}else{
this.ul.setHeight(full);
this.el.select('.x-menu-scroller').setDisplayed('none');
}
this.ul.dom.scrollTop = 0;
return new_y;
}