Browse Source

Begin rewrite of popup calcs to cache correctly on each position check

pull/2369/head
jlukic 9 years ago
parent
commit
794d082218
1 changed files with 134 additions and 93 deletions
  1. 227
      src/definitions/modules/popup.js

227
src/definitions/modules/popup.js

@ -59,6 +59,7 @@ $.fn.popup = function(parameters) {
searchDepth = 0,
triedPositions = false,
openedWithTouch = false,
element = this,
instance = $module.data(moduleNamespace),
@ -166,10 +167,24 @@ $.fn.popup = function(parameters) {
clearTimeout(module.showTimer);
module.hideTimer = setTimeout(module.hide, delay);
},
touchstart: function(event) {
openedWithTouch = true;
module.event.start();
},
resize: function() {
if( module.is.visible() ) {
module.set.position();
}
},
hideGracefully: function(event) {
// don't close on clicks inside popup
if(event && $(event.target).closest(selector.popup).length === 0) {
module.debug('Click occurred outside popup hiding popup');
module.hide();
}
else {
module.debug('Click was inside popup, keeping popup open');
}
}
},
@ -312,18 +327,6 @@ $.fn.popup = function(parameters) {
})
;
},
hideGracefully: function(event) {
// don't close on clicks inside popup
if(event && $(event.target).closest(selector.popup).length === 0) {
module.debug('Click occurred outside popup hiding popup');
module.hide();
}
else {
module.debug('Click was inside popup, keeping popup open');
}
},
exists: function() {
if(!$popup) {
return false;
@ -438,15 +441,51 @@ $.fn.popup = function(parameters) {
$module.removeData(metadata.variation);
return $module.data(metadata.variation) || settings.variation;
},
sizes: function() {
var
targetElement = $target[0],
sizes = {}
;
// grab position
sizes.target = (settings.inline || settings.popup)
? $target.position()
: $target.offset()
;
sizes = {
target: {
element : $target[0],
width : $target.outerWidth(),
height : $target.outerHeight(),
margin : {}
},
popup: {
width: $popup.outerWidth(),
height: $popup.outerHeight()
},
parent: {
width: $offsetParent.outerWidth(),
height: $offsetParent.outerHeight()
}
};
sizes.target.margin.top = (settings.inline)
? parseInt( window.getComputedStyle(targetElement).getPropertyValue('margin-top'), 10)
: 0
;
sizes.target.margin.left = (settings.inline)
? module.is.rtl()
? parseInt( window.getComputedStyle(targetElement).getPropertyValue('margin-right'), 10)
: parseInt( window.getComputedStyle(targetElement).getPropertyValue('margin-left') , 10)
: 0
;
return sizes;
},
id: function() {
return id;
},
startEvent: function() {
if(settings.on == 'hover') {
return (hasTouch && settings.addTouchEvents)
? 'touchstart mouseenter'
: 'mouseenter'
;
return 'mouseenter';
}
else if(settings.on == 'focus') {
return 'focus';
@ -454,10 +493,7 @@ $.fn.popup = function(parameters) {
return false;
},
scrollEvent: function() {
return (hasTouch && settings.addTouchEvents)
? 'touchmove scroll'
: 'scroll'
;
return 'scroll';
},
endEvent: function() {
if(settings.on == 'hover') {
@ -510,8 +546,8 @@ $.fn.popup = function(parameters) {
right : screen.left + screen.width
},
popup = {
width : $popup.width(),
height : $popup.height(),
width : $popup.outerWidth(),
height : $popup.outerHeight(),
offset : $popup.offset()
},
offstage = {},
@ -610,7 +646,7 @@ $.fn.popup = function(parameters) {
},
set: {
position: function(position, arrowOffset) {
position: function(position, sizes) {
// exit conditions
if($target.length === 0 || $popup.length === 0) {
@ -618,140 +654,125 @@ $.fn.popup = function(parameters) {
return;
}
var
windowWidth = $(window).width(),
windowHeight = $(window).height(),
targetWidth = $target.outerWidth(),
targetHeight = $target.outerHeight(),
popupWidth = $popup.outerWidth(),
popupHeight = $popup.outerHeight(),
parentWidth = $offsetParent.outerWidth(),
parentHeight = $offsetParent.outerHeight(),
distanceAway = settings.distanceAway,
targetElement = $target[0],
marginTop = (settings.inline)
? parseInt( window.getComputedStyle(targetElement).getPropertyValue('margin-top'), 10)
: 0,
marginLeft = (settings.inline)
? module.is.rtl()
? parseInt( window.getComputedStyle(targetElement).getPropertyValue('margin-right'), 10)
: parseInt( window.getComputedStyle(targetElement).getPropertyValue('margin-left') , 10)
: 0,
target = (settings.inline || settings.popup)
? $target.position()
: $target.offset(),
offset,
distanceAway,
target,
popup,
parent,
computedPosition,
positioning,
offstagePosition
;
position = position || $module.data(metadata.position) || settings.position;
arrowOffset = arrowOffset || $module.data(metadata.offset) || settings.offset;
sizes = sizes || module.get.sizes();
position = position || $module.data(metadata.position) || settings.position;
offset = $module.data(metadata.offset) || settings.offset;
distanceAway = settings.distanceAway;
// shorthand
target = sizes.target;
popup = sizes.popup;
parent = sizes.parent;
if(target.top === 0 && target.left === 0) {
module.debug('Popup target is hidden, no action taken');
return false;
}
if(searchDepth == settings.maxSearchDepth && settings.lastResort) {
module.debug('Using last resort position to display', settings.lastResort);
position = settings.lastResort;
}
if(settings.inline) {
module.debug('Adding targets margin to calculation');
if(position == 'left center' || position == 'right center') {
arrowOffset += marginTop;
distanceAway += -marginLeft;
offset += target.margin.top;
distanceAway += -target.margin.left;
}
else if (position == 'top left' || position == 'top center' || position == 'top right') {
arrowOffset += marginLeft;
distanceAway -= marginTop;
offset += target.margin.left;
distanceAway -= target.margin.top;
}
else {
arrowOffset += marginLeft;
distanceAway += marginTop;
offset += target.margin.left;
distanceAway += target.margin.top;
}
}
module.debug('Calculating popup positioning', position);
computedPosition = position;
if (module.is.rtl()) {
computedPosition = computedPosition.replace(/left|right/g, function (match) {
position = position.replace(/left|right/g, function (match) {
return (match == 'left')
? 'right'
: 'left'
;
});
module.debug('RTL: Popup positioning updated', computedPosition);
module.debug('RTL: Popup positioning updated', position);
}
if(searchDepth == settings.maxSearchDepth && settings.lastResort) {
module.debug('Using last resort position to display', settings.lastResort);
position = settings.lastResort;
}
switch (computedPosition) {
switch (position) {
case 'top left':
positioning = {
top : 'auto',
bottom : parentHeight - target.top + distanceAway,
left : target.left + arrowOffset,
bottom : parent.height - target.top + distanceAway,
left : target.left + offset,
right : 'auto'
};
break;
case 'top center':
positioning = {
bottom : parentHeight - target.top + distanceAway,
left : target.left + (targetWidth / 2) - (popupWidth / 2) + arrowOffset,
bottom : parent.height - target.top + distanceAway,
left : target.left + (target.width / 2) - (popup.width / 2) + offset,
top : 'auto',
right : 'auto'
};
break;
case 'top right':
positioning = {
bottom : parentHeight - target.top + distanceAway,
right : parentWidth - target.left - targetWidth - arrowOffset,
bottom : parent.height - target.top + distanceAway,
right : parent.width - target.left - target.width - offset,
top : 'auto',
left : 'auto'
};
break;
case 'left center':
positioning = {
top : target.top + (targetHeight / 2) - (popupHeight / 2) + arrowOffset,
right : parentWidth - target.left + distanceAway,
top : target.top + (target.height / 2) - (popup.height / 2) + offset,
right : parent.width - target.left + distanceAway,
left : 'auto',
bottom : 'auto'
};
break;
case 'right center':
positioning = {
top : target.top + (targetHeight / 2) - (popupHeight / 2) + arrowOffset,
left : target.left + targetWidth + distanceAway,
top : target.top + (target.height / 2) - (popup.height / 2) + offset,
left : target.left + target.width + distanceAway,
bottom : 'auto',
right : 'auto'
};
break;
case 'bottom left':
positioning = {
top : target.top + targetHeight + distanceAway,
left : target.left + arrowOffset,
top : target.top + target.height + distanceAway,
left : target.left + offset,
bottom : 'auto',
right : 'auto'
};
break;
case 'bottom center':
positioning = {
top : target.top + targetHeight + distanceAway,
left : target.left + (targetWidth / 2) - (popupWidth / 2) + arrowOffset,
top : target.top + target.height + distanceAway,
left : target.left + (target.width / 2) - (popup.width / 2) + offset,
bottom : 'auto',
right : 'auto'
};
break;
case 'bottom right':
positioning = {
top : target.top + targetHeight + distanceAway,
right : parentWidth - target.left - targetWidth - arrowOffset,
top : target.top + target.height + distanceAway,
right : parent.width - target.left - target.width - offset,
left : 'auto',
bottom : 'auto'
};
@ -781,7 +802,7 @@ $.fn.popup = function(parameters) {
position = module.get.nextPosition(position);
module.debug('Trying new position', position);
return ($popup)
? module.set.position(position)
? module.set.position(position, sizes)
: false
;
}
@ -835,6 +856,11 @@ $.fn.popup = function(parameters) {
.on('click' + eventNamespace, module.toggle)
;
}
if(settings.on == 'hover' && hasTouch) {
$module
.on('touchstart' + eventNamespace, module.event.touchstart)
;
}
else if( module.get.startEvent() ) {
$module
.on(module.get.startEvent() + eventNamespace, module.event.start)
@ -855,21 +881,30 @@ $.fn.popup = function(parameters) {
;
}
},
close:function() {
if(settings.hideOnScroll === true || settings.hideOnScroll == 'auto' && settings.on != 'click') {
close: function() {
if(settings.hideOnScroll === true || (settings.hideOnScroll == 'auto' && settings.on != 'click')) {
$document
.one(module.get.scrollEvent() + elementNamespace, module.hideGracefully)
.one(module.get.scrollEvent() + elementNamespace, module.event.hideGracefully)
;
$context
.one(module.get.scrollEvent() + elementNamespace, module.hideGracefully)
.one(module.get.scrollEvent() + elementNamespace, module.event.hideGracefully)
;
}
if(settings.on == 'hover' && openedWithTouch) {
module.verbose('Binding popup close event to document');
$document
.on('touchstart' + elementNamespace, function(event) {
module.verbose('Touched away from popup');
module.event.hideGracefully.call(element, event);
})
;
}
if(settings.on == 'click' && settings.closable) {
module.verbose('Binding popup close event to document');
$document
.on('click' + elementNamespace, function(event) {
module.verbose('Pop-up clickaway intent detected');
module.hideGracefully.call(element, event);
module.verbose('Clicked away from popup');
module.event.hideGracefully.call(element, event);
})
;
}
@ -878,7 +913,7 @@ $.fn.popup = function(parameters) {
unbind: {
close: function() {
if(settings.hideOnScroll === true || settings.hideOnScroll == 'auto' && settings.on != 'click') {
if(settings.hideOnScroll === true || (settings.hideOnScroll == 'auto' && settings.on != 'click')) {
$document
.off('scroll' + elementNamespace, module.hide)
;
@ -886,6 +921,12 @@ $.fn.popup = function(parameters) {
.off('scroll' + elementNamespace, module.hide)
;
}
if(settings.on == 'hover' && openedWithTouch) {
$document
.off('touchstart' + elementNamespace)
;
openedWithTouch = false;
}
if(settings.on == 'click' && settings.closable) {
module.verbose('Removing close event from document');
$document

Loading…
Cancel
Save