Skip to content

Commit

Permalink
Added support for a reference el that is both fixed and transformed. (#…
Browse files Browse the repository at this point in the history
  • Loading branch information
hgascoigne authored and FezVrasta committed Jul 7, 2016
1 parent 228161b commit 0a79027
Show file tree
Hide file tree
Showing 2 changed files with 63 additions and 3 deletions.
36 changes: 33 additions & 3 deletions src/popper.js
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,9 @@
this.state.position = this._getPosition(this._popper, this._reference);
setStyle(this._popper, { position: this.state.position});

// determine how we should set the origin of offsets
this.state.isParentTransformed = this._getIsParentTransformed(this._popper);

// fire the first update to position the popper in the right place
this.update();

Expand Down Expand Up @@ -378,6 +381,15 @@
return isParentFixed ? 'fixed' : 'absolute';
};

/**
* Helper used to determine if the popper's parent is transformed.
* @param {[type]} popper [description]
* @return {[type]} [description]
*/
Popper.prototype._getIsParentTransformed = function(popper) {
return isTransformed(popper.parentNode);
};

/**
* Get offsets to the popper
* @method
Expand All @@ -394,10 +406,13 @@
popperOffsets.position = this.state.position;
var isParentFixed = popperOffsets.position === 'fixed';

var isParentTransformed = this.state.isParentTransformed;

//
// Get reference element position
//
var referenceOffsets = getOffsetRectRelativeToCustomParent(reference, getOffsetParent(popper), isParentFixed);
var offsetParent = (isParentFixed && isParentTransformed) ? getOffsetParent(reference) : getOffsetParent(popper);
var referenceOffsets = getOffsetRectRelativeToCustomParent(reference, offsetParent, isParentFixed, isParentTransformed);

//
// Get popper sizes
Expand Down Expand Up @@ -1075,6 +1090,21 @@
return element.parentNode ? isFixed(element.parentNode) : element;
}

/**
* Check if the given element has transforms applied to itself or a parent
* @param {Element} element
* @return {Boolean} answer to "isTransformed?"
*/
function isTransformed(element) {
if (element === root.document.body) {
return false;
}
if (getStyleComputedProperty(element, 'transform') !== 'none') {
return true;
}
return element.parentNode ? isTransformed(element.parentNode) : element;
}

/**
* Set the style to the given popper
* @function
Expand Down Expand Up @@ -1157,11 +1187,11 @@
* @param {HTMLElement} parent
* @return {Object} rect
*/
function getOffsetRectRelativeToCustomParent(element, parent, fixed) {
function getOffsetRectRelativeToCustomParent(element, parent, fixed, transformed) {
var elementRect = getBoundingClientRect(element);
var parentRect = getBoundingClientRect(parent);

if (fixed) {
if (fixed && !transformed) {
var scrollParent = getScrollParent(parent);
parentRect.top += scrollParent.scrollTop;
parentRect.bottom += scrollParent.scrollTop;
Expand Down
30 changes: 30 additions & 0 deletions tests/test-popper.js
Original file line number Diff line number Diff line change
Expand Up @@ -203,6 +203,36 @@ describe('Popper.js', function() {
});
});

it('inits a popper near a reference element, both inside a fixed element with CSS transforms, inside a scrolled body', function(done) {
var fixed = document.createElement('div');
fixed.style.position = 'fixed';
fixed.style.margin = '20px';
fixed.style.height = '50px';
fixed.style.width = '100%';
fixed.style.transform = 'translateX(0)'
jasmineWrapper.appendChild(fixed);

var relative = document.createElement('div');
relative.style.position = 'relative';
relative.style.margin = '20px';
relative.style.height = '200vh';
jasmineWrapper.appendChild(relative);
document.body.scrollTop = 800;

var ref = appendNewRef(1, 'ref', fixed);
var popper = appendNewPopper(2, 'popper', fixed);

new TestPopper(ref, popper).onCreate(function(pop) {
// force redraw
window.dispatchEvent(new Event('resize'));

expect(popper.getBoundingClientRect().top).toBeApprox(83);
expect(popper.getBoundingClientRect().left).toBeApprox(33);
pop.destroy();
done();
});
});

it('inits a popper near a reference element, both inside a fixed element on bottom of viewport, inside a scrolled body', function(done) {
var fixed = document.createElement('div');
fixed.style.position = 'fixed';
Expand Down

0 comments on commit 0a79027

Please sign in to comment.