MDL-47734 core: Prevent jumping of YUI dialogues

When a YUI dialogue was opened, it was focusing on the boundingBox, with
the browser moving the scroll position to focus on the top of the
boundingBox. This caused a jump. This only happens when the dialogue is
modal and consequentially has a maskNode present as it changes the initial
positioning behaviour of the boundingBox.

To avoid this, when the maskNode is shown, the dialogue is position at 0,0
in the current viewport. For centered dialogues, the dialogue is
automatically re-positioned after the window has shown. For non-centered
dialogues, the original position is stored and the dialogue is restored to
that position after it has been displayed.

This should not interfere with use of the align function as this will be
called later in the proceedings, after the show has run.
This commit is contained in:
Andrew Nicols 2014-10-23 14:44:14 +08:00
parent b1b66a3d12
commit d247a50113
4 changed files with 95 additions and 29 deletions

View File

@ -98,6 +98,16 @@ Y.extend(DIALOGUE, Y.Panel, {
_orientationevent : null,
_calculatedzindex : false,
/**
* The original position of the dialogue before it was reposition to
* avoid browser jumping.
*
* @property _originalPosition
* @protected
* @type Array
*/
_originalPosition: null,
/**
* Initialise the dialogue.
*
@ -132,14 +142,21 @@ Y.extend(DIALOGUE, Y.Panel, {
}
// Recalculate the zIndex every time the modal is altered.
this.on('maskShow', this.applyZIndex);
// We must show - after the dialogue has been positioned,
// either by centerDialogue or makeResonsive. This is because the show() will trigger
// a focus on the dialogue, which will scroll the page. If the dialogue has not
// been positioned it will scroll back to the top of the page.
if (this.get('visible')) {
this.show();
this.keyDelegation();
}
this.on('maskShow', function() {
// When the mask shows, position the boundingBox at the top-left of the window such that when it is
// focused, the position does not change.
var w = Y.one(Y.config.win),
bb = this.get('boundingBox');
if (!this.get('center')) {
this._originalPosition = bb.getXY();
}
bb.setStyles({
top: w.get('scrollTop'),
left: w.get('scrollLeft')
});
}, this);
// Remove the dialogue from the DOM when it is destroyed.
this.after('destroyedChange', function(){
@ -325,7 +342,7 @@ Y.extend(DIALOGUE, Y.Panel, {
Math.floor(Y.one(document.body).get('winWidth')) < this.get('responsiveWidth');
},
show : function() {
show: function() {
var result = null,
header = this.headerNode,
content = this.bodyNode,
@ -334,6 +351,11 @@ Y.extend(DIALOGUE, Y.Panel, {
result = DIALOGUE.superclass.show.call(this);
if (!this.get('center') && this._originalPosition) {
// Restore the dialogue position to it's location before it was moved at show time.
this.get('boundingBox').setXY(this._originalPosition);
}
// Lock scroll if the plugin is present.
if (this.lockScroll) {
// We need to force the scroll locking for full screen dialogues, even if they have a small vertical size to

File diff suppressed because one or more lines are too long

View File

@ -98,6 +98,16 @@ Y.extend(DIALOGUE, Y.Panel, {
_orientationevent : null,
_calculatedzindex : false,
/**
* The original position of the dialogue before it was reposition to
* avoid browser jumping.
*
* @property _originalPosition
* @protected
* @type Array
*/
_originalPosition: null,
/**
* Initialise the dialogue.
*
@ -132,14 +142,21 @@ Y.extend(DIALOGUE, Y.Panel, {
}
// Recalculate the zIndex every time the modal is altered.
this.on('maskShow', this.applyZIndex);
// We must show - after the dialogue has been positioned,
// either by centerDialogue or makeResonsive. This is because the show() will trigger
// a focus on the dialogue, which will scroll the page. If the dialogue has not
// been positioned it will scroll back to the top of the page.
if (this.get('visible')) {
this.show();
this.keyDelegation();
}
this.on('maskShow', function() {
// When the mask shows, position the boundingBox at the top-left of the window such that when it is
// focused, the position does not change.
var w = Y.one(Y.config.win),
bb = this.get('boundingBox');
if (!this.get('center')) {
this._originalPosition = bb.getXY();
}
bb.setStyles({
top: w.get('scrollTop'),
left: w.get('scrollLeft')
});
}, this);
// Remove the dialogue from the DOM when it is destroyed.
this.after('destroyedChange', function(){
@ -325,7 +342,7 @@ Y.extend(DIALOGUE, Y.Panel, {
Math.floor(Y.one(document.body).get('winWidth')) < this.get('responsiveWidth');
},
show : function() {
show: function() {
var result = null,
header = this.headerNode,
content = this.bodyNode,
@ -334,6 +351,11 @@ Y.extend(DIALOGUE, Y.Panel, {
result = DIALOGUE.superclass.show.call(this);
if (!this.get('center') && this._originalPosition) {
// Restore the dialogue position to it's location before it was moved at show time.
this.get('boundingBox').setXY(this._originalPosition);
}
// Lock scroll if the plugin is present.
if (this.lockScroll) {
// We need to force the scroll locking for full screen dialogues, even if they have a small vertical size to

View File

@ -69,6 +69,16 @@ Y.extend(DIALOGUE, Y.Panel, {
_orientationevent : null,
_calculatedzindex : false,
/**
* The original position of the dialogue before it was reposition to
* avoid browser jumping.
*
* @property _originalPosition
* @protected
* @type Array
*/
_originalPosition: null,
/**
* Initialise the dialogue.
*
@ -103,14 +113,21 @@ Y.extend(DIALOGUE, Y.Panel, {
}
// Recalculate the zIndex every time the modal is altered.
this.on('maskShow', this.applyZIndex);
// We must show - after the dialogue has been positioned,
// either by centerDialogue or makeResonsive. This is because the show() will trigger
// a focus on the dialogue, which will scroll the page. If the dialogue has not
// been positioned it will scroll back to the top of the page.
if (this.get('visible')) {
this.show();
this.keyDelegation();
}
this.on('maskShow', function() {
// When the mask shows, position the boundingBox at the top-left of the window such that when it is
// focused, the position does not change.
var w = Y.one(Y.config.win),
bb = this.get('boundingBox');
if (!this.get('center')) {
this._originalPosition = bb.getXY();
}
bb.setStyles({
top: w.get('scrollTop'),
left: w.get('scrollLeft')
});
}, this);
// Remove the dialogue from the DOM when it is destroyed.
this.after('destroyedChange', function(){
@ -296,7 +313,7 @@ Y.extend(DIALOGUE, Y.Panel, {
Math.floor(Y.one(document.body).get('winWidth')) < this.get('responsiveWidth');
},
show : function() {
show: function() {
var result = null,
header = this.headerNode,
content = this.bodyNode,
@ -305,6 +322,11 @@ Y.extend(DIALOGUE, Y.Panel, {
result = DIALOGUE.superclass.show.call(this);
if (!this.get('center') && this._originalPosition) {
// Restore the dialogue position to it's location before it was moved at show time.
this.get('boundingBox').setXY(this._originalPosition);
}
// Lock scroll if the plugin is present.
if (this.lockScroll) {
// We need to force the scroll locking for full screen dialogues, even if they have a small vertical size to