From 8e6b5ddc0ad25eb873848105add15f6a45dfc2ec Mon Sep 17 00:00:00 2001 From: jlukic Date: Tue, 2 Dec 2014 17:01:05 -0500 Subject: [PATCH] Popup: Adds better popup positioning, new settings for popup positioning strategy , and a last resort position if it cannot fit on stage --- src/definitions/modules/popup.js | 229 ++++++++++++++++++++----------- 1 file changed, 148 insertions(+), 81 deletions(-) diff --git a/src/definitions/modules/popup.js b/src/definitions/modules/popup.js index 87239df18..1f3339601 100644 --- a/src/definitions/modules/popup.js +++ b/src/definitions/modules/popup.js @@ -37,30 +37,31 @@ $.fn.popup = function(parameters) { ? $.extend(true, {}, $.fn.popup.settings, parameters) : $.extend({}, $.fn.popup.settings), - selector = settings.selector, - className = settings.className, - error = settings.error, - metadata = settings.metadata, - namespace = settings.namespace, - - eventNamespace = '.' + settings.namespace, - moduleNamespace = 'module-' + namespace, - - $module = $(this), - $context = $(settings.context), - $target = (settings.target) + selector = settings.selector, + className = settings.className, + error = settings.error, + metadata = settings.metadata, + namespace = settings.namespace, + + eventNamespace = '.' + settings.namespace, + moduleNamespace = 'module-' + namespace, + + $module = $(this), + $context = $(settings.context), + $target = (settings.target) ? $(settings.target) : $module, - $window = $(window), - $body = $('body'), + $window = $(window), + $body = $('body'), $popup, $offsetParent, - searchDepth = 0, + searchDepth = 0, + triedPositions = false, - element = this, - instance = $module.data(moduleNamespace), + element = this, + instance = $module.data(moduleNamespace), module ; @@ -440,7 +441,7 @@ $.fn.popup = function(parameters) { top : (popup.offset.top < boundary.top), bottom : (popup.offset.top + popup.height > boundary.bottom), right : (popup.offset.left + popup.width > boundary.right), - left : false + left : (popup.offset.left < boundary.left) }; } // return only boundaries that have been surpassed @@ -454,34 +455,75 @@ $.fn.popup = function(parameters) { : false ; }, + positions: function() { + return { + 'top left' : false, + 'top center' : false, + 'top right' : false, + 'bottom left' : false, + 'bottom center' : false, + 'bottom right' : false, + 'left center' : false, + 'right center' : false + }; + }, nextPosition: function(position) { - switch(position) { - case 'top left': - position = 'bottom left'; - break; - case 'bottom left': - position = 'top right'; - break; - case 'top right': - position = 'bottom right'; - break; - case 'bottom right': - position = 'top center'; - break; - case 'top center': - position = 'bottom center'; - break; - case 'bottom center': - position = 'right center'; - break; - case 'right center': - position = 'left center'; - break; - case 'left center': - position = 'top center'; - break; + var + positions = position.split(' '), + verticalPosition = positions[0], + horizontalPosition = positions[1], + opposite = { + top : 'bottom', + bottom : 'top', + left : 'right', + right : 'left' + }, + adjacent = { + left : 'center', + center : 'right', + right : 'left' + }, + backup = { + 'top left' : 'top center', + 'top center' : 'top right', + 'top right' : 'right center', + 'right center' : 'bottom right', + 'bottom right' : 'bottom center', + 'bottom center' : 'bottom left', + 'bottom left' : 'left center', + 'left center' : 'top left' + }, + adjacentsAvailable = (verticalPosition == 'top' || verticalPosition == 'bottom'), + oppositeTried = false, + adjacentTried = false, + nextPosition = false + ; + if(!triedPositions) { + module.verbose('All available positions available'); + triedPositions = module.get.positions(); } - return position; + + module.debug('Recording last position tried', position); + triedPositions[position] = true; + + if(settings.prefer === 'opposite') { + nextPosition = [opposite[verticalPosition], horizontalPosition]; + nextPosition = nextPosition.join(' '); + oppositeTried = (triedPositions[nextPosition] === true); + module.debug('Trying opposite strategy', nextPosition); + } + if((settings.prefer === 'adjacent') && adjacentsAvailable ) { + nextPosition = [verticalPosition, adjacent[horizontalPosition]]; + nextPosition = nextPosition.join(' '); + adjacentTried = (triedPositions[nextPosition] === true); + module.debug('Trying adjacent strategy', nextPosition); + } + if(adjacentTried || oppositeTried) { + module.debug('Using backup position', nextPosition); + nextPosition = backup[position]; + } + console.log(nextPosition); + return nextPosition; } }, @@ -520,6 +562,12 @@ $.fn.popup = function(parameters) { ; position = position || $module.data(metadata.position) || settings.position; arrowOffset = arrowOffset || $module.data(metadata.offset) || settings.offset; + + 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') { @@ -603,8 +651,9 @@ $.fn.popup = function(parameters) { break; } if(positioning === undefined) { - module.error(error.invalidPosition); + module.error(error.invalidPosition, position); } + // tentatively place on stage $popup .css(positioning) @@ -617,32 +666,37 @@ $.fn.popup = function(parameters) { // recursively find new positioning if(offstagePosition) { - module.debug('Element is outside boundaries', offstagePosition); + module.debug('Popup cant fit into viewport', offstagePosition); if(searchDepth < settings.maxSearchDepth) { - position = module.get.nextPosition(position); searchDepth++; + position = module.get.nextPosition(position); module.debug('Trying new position', position); return ($popup) ? module.set.position(position) : false ; } - else { - module.debug('Popup could not find a position onstage', $popup); - searchDepth = 0; + else if(!settings.lastResort) { + module.debug('Popup could not find a position in view', $popup); + module.error(error.cannotPlace); + module.remove.attempts(); + module.remove.loading(); module.reset(); - $popup.removeClass(className.loading); return false; } } - else { - module.debug('Position is on stage', position); - searchDepth = 0; - if( settings.setFluidWidth && $popup.hasClass(className.fluid) ) { - $popup.css('width', $offsetParent.width()); - } - $popup.removeClass(className.loading); - return true; + + module.debug('Position is on stage', position); + module.remove.attempts(); + module.set.fluidWidth(); + module.remove.loading(); + console.log('worked', position); + return true; + }, + + fluidWidth: function() { + if( settings.setFluidWidth && $popup.hasClass(className.fluid) ) { + $popup.css('width', $offsetParent.width()); } }, @@ -652,8 +706,16 @@ $.fn.popup = function(parameters) { }, remove: { + loading: function() { + $popup.removeClass(className.loading); + }, visible: function() { $module.removeClass(className.visible); + }, + attempts: function() { + module.verbose('Resetting all searched positions'); + searchDepth = 0; + triedPositions = false; } }, @@ -918,33 +980,37 @@ $.fn.popup = function(parameters) { $.fn.popup.settings = { - name : 'Popup', + name : 'Popup', + + debug : false, + verbose : true, + performance : true, + namespace : 'popup', + + onCreate : function(){}, + onRemove : function(){}, - debug : false, - verbose : true, - performance : true, - namespace : 'popup', + onShow : function(){}, + onVisible : function(){}, + onHide : function(){}, + onHidden : function(){}, - onCreate : function(){}, - onRemove : function(){}, + variation : '', + content : false, + html : false, + title : false, - onShow : function(){}, - onVisible : function(){}, - onHide : function(){}, - onHidden : function(){}, + on : 'hover', + closable : true, + hideOnScroll : 'auto', - variation : '', - content : false, - html : false, - title : false, + context : 'body', - on : 'hover', - closable : true, - hideOnScroll : 'auto', + position : 'top left', + prefer : 'opposite', + lastResort : false, - context : 'body', - position : 'top left', - delay : { + delay : { show : 30, hide : 0 }, @@ -963,10 +1029,11 @@ $.fn.popup.settings = { distanceAway : 0, offset : 0, - maxSearchDepth : 10, + maxSearchDepth : 20, error: { invalidPosition : 'The position you specified is not a valid position', + cannotPlace : 'No visible position could be found for the popup', method : 'The method you called is not defined.' },