(function(MD) { var positionoptions = { topleft: 1, upperleft: 1, centertop: 2, topcenter: 2, topright: 3, upperright: 3, centerright: 4, rightcenter: 4, bottomright: 5, lowerright: 5, centerbottom: 6, bottomcenter: 6, bottomleft: 7, centerleft: 8, leftcenter: 8 }; MD.Popover = new Class({ Implements: [Events, Options, MD.Spin] ,options: { className: '' ,forcePosition: false ,pointTo: null ,relativeTo: null ,content: null ,height: null ,width: null ,minWidth: null // if you have a min width, then the width will be at least this number ,offset: {} // only when forcePosition = true ,position: 'centerTop' // topLeft, topCenter, topRight, rightCenter, bottomRight, bottomCenter, bottomLeft, left ,edge: 'auto' ,showNipple: true // nipple is only for the non modal version ,closeButton: true ,closeButtonAction: null // pass a function to override the default ,clickToClose: false ,styles: {} // Mask ,maskTarget: null ,maskOptions: { color: '#000' ,opacity: 0.7 } ,zIndex: 5000 ,exclusive: true ,exclusiveImmune: false ,clickOutsideToClose: true ,allowPointToToNoDoClickout: true ,destroyOnHide: true ,destroyContent: true ,timeout: null ,positionFx: true ,injectInto: null // ,onShow: function(thisObj){} // ,onHide: function(thisObj){} // ,onShow:before (this) // ,onShow:after (this) } ,initialize: function(options){ this.setOptions(options); // Set up the MD.PopoverStack MD.PopoverStack = MD.PopoverStack || []; this.id = String.uniqueID(); this.maskOptions = this.options.maskOptions; this.pointTo = this.options.pointTo; this.showing = false; this.uniqueId = String.uniqueID(); if ( ! this.options.position) { this.options.position = 'centerTop'; } if ( ! this.options.edge) { this.options.edge = 'auto'; } if (this.options.forcePosition) { this.offset = this.options.offset; this.offset.x = this.offset.x || 0; this.offset.y = this.offset.y || 0; } else { this.offset = {x: 0, y: 0}; } this.exclusiveImmune = this.options.exclusiveImmune; this.build(); } ,build: function() { this.html = new Element('div', { 'class':'MDPopover '+this.options.className ,id: this.id ,styles:{ position: 'absolute' ,opacity: 0 ,display: 'none' ,visibility: 'hidden' ,top: 0 ,left: 0 } ,morph: {duration:200} ,tween: {duration:200} }).adopt(this.contentContainer = new Element('div.MDPopover-Content')); if (this.options.closeButton) { this.closeButton = new MD.Input.Button({ text: 'close' ,className: 'MDPopover-CloseButton' ,onClick: function(ev){ ev.stop(); if (this.options.closeButtonAction) { this.options.closeButtonAction(this); } else { this.hide(); } }.bind(this) }); this.closeButton.toElement.hide(); this.html.adopt(this.closeButton); } if (this.options.content) { this.setContent(this.options.content); } // Make sure this one has the highest zIndex this.zIndex = this.options.zIndex; if (MD.PopoverStack.length > 0 && this.options.zIndex !== false) { // change to always manual set zindex var highestZindex = 0; MD.PopoverStack.each(function(i) { if (i.zIndex.toInt() > highestZindex) { highestZindex = i.zIndex.toInt(); } }); this.zIndex = highestZindex + 50; if (this.zIndex < this.options.zIndex) { this.zIndex = this.options.zIndex; } } // Set the zIndex on the main element... this.html.setStyle('z-index', this.zIndex); this.targetElement = this.options.maskTarget;//(this.options.injectInto ? this.options.injectInto.getParent() : $$('body')[0]); var injectInto = this._getInjectInto(); injectInto.grab(this.html); // Store the object in the main HTML element this.html.store('object', this); return this; } ,show: function(){ this.fireEvent('show:before', this); if (this.options.exclusive) { MD.PopoverStack.each(function(popover) { if (!popover.exclusiveImmune) { popover.hide(); } }); } if (this.showing) { return; } if (!this.html) { this.initialize(); } if (this.options.maskTarget) { this.mask = new Mask(this.targetElement, Object.merge({ destroyOnHide: true ,style:{ opacity:this.maskOptions.opacity ,'background-color':this.maskOptions.color ,'z-index': this.zIndex - 1 } }, this.options.maskOptions)); } if (this.mask) { this.mask.show(); } // POSITION IT this.positionAndDisplay(); if (this.options.clickToClose) { this.html.setStyle('cursor', 'pointer').addEvent('click', function(){ this.hide(); }.bind(this)); } this.fireEvent('show', this, 250); // Add the event(s) to close if (this.options.clickOutsideToClose) { if ( ! this._clickoutFunction) { this._clickoutFunction = function(event) { //e.stopPropagation(); var target = event.target; if (target !== this.pointTo && this.options.allowPointToToNoDoClickout) { try { this.hide(); } catch(error){ console.error(error); } } }.bind(this); } this.html.addEvent('clickout', this._clickoutFunction); } // Show the close button if we need to... if (this.options.closeButton) { this.closeButton.toElement().show(); } this.showing = true; MD.PopoverStack.push(this); if (this.options.timeout) (function(){ this.hide(); }.bind(this)).delay(this.options.timeout); this.fireEvent('show:after', this, 250); return this; } ,positionAndDisplay: function() { // Set up morph FX instance... this.morphToPosition = new Fx.Morph(this.html, { duration: 200 ,transition: Fx.Transitions.Sine.easeOut ,link: 'chain' ,onChainComplete: function(){ // if(this.options.centerOnPage) this.html.tween('opacity', [0,1]); }.bind(this) }); if (this.pointTo) { // setup nipple if (this.nipple && this.nipple.isDisplayed()) { this.nipple.destroy(); delete this.nipple; } this._doPointTo(); } else { this._doModal(); } } ,_getMaxHeightWhenForcePosition: function(parentCoordinates, pointCords, positionNumber) { var maxHeight = parentCoordinates.height-25; switch (positionNumber) { case 1: case 2: case 3: maxHeight = pointCords.top - 25; break; case 4: case 8: maxHeight = parentCoordinates.bottom - (pointCords.bottom + pointCords.height/2) - 25; break; case 5: case 6: case 7: maxHeight = parentCoordinates.bottom - (pointCords.bottom) - 25; break; } return maxHeight; } ,_doPointTo: function() { var popoverDimensions = this._computeDimensions(); this.showNipple = this.options.showNipple; // TODO: This could get some better logic. Like first test using hte injectINtoCords // which tests the height of inject into area. Then if all fails, try again with window // maybe some tests to try different edge/position combinations as well var positionNumber = positionoptions[this.options.position.toLowerCase()] || 1; var injectIntoCords = this._getInjectInto().getCoordinates(); var pointCords = this.pointTo.getCoordinates(this._getInjectInto()); var injectScroll = this._getInjectInto().getScroll(); var maxHeight = this.windowCoordinates.height-25; if (this.options.forcePosition) { maxHeight = this._getMaxHeightWhenForcePosition(this.windowCoordinates, pointCords, positionNumber); } this.html.setStyles(Object.merge({ height: this.height ,width: this.width ,'max-height': maxHeight ,'max-width': this.windowCoordinates.width-25 ,opacity: 0 ,visibility: 'hidden' ,display: 'block' }, this.options.styles)); pointCords.left += injectScroll.x; pointCords.top += injectScroll.y; // dont like the way of setting this var and just using it in _testPosition, but live with it this.edge = this.options.edge; // this is what the user passed in the options var result = {success: false}; var currentLoopIndex = 0; var positionNumbers; // it is forced, just do it!!!! if (this.options.forcePosition) { result = this._testPosition(positionNumber, popoverDimensions, pointCords, injectIntoCords, injectScroll); positionNumbers = [{ point: positionNumber }]; } else { // get list of positions to use positionNumbers = this._getPositionNumbersToTest(positionNumber, pointCords, injectIntoCords); } currentLoopIndex = 0; // try to use the specified edge if (this.edge !== "auto" && ! this.options.forcePosition) { // do it while ( ! result.success && positionNumbers.length > currentLoopIndex) { result = this._testPosition(positionNumbers[currentLoopIndex].point, popoverDimensions, pointCords, injectIntoCords, injectScroll); currentLoopIndex += 1; } this.edge = "auto"; } // non auto edge failed, or not set if ( ! result.success && ! this.options.forcePosition) { currentLoopIndex = 0; // do it while ( ! result.success && positionNumbers.length > currentLoopIndex) { result = this._testPosition(positionNumbers[currentLoopIndex].point, popoverDimensions, pointCords, injectIntoCords, injectScroll); currentLoopIndex += 1; } } var body = $$('body')[0]; if ( ! result.success) { var parent = this._getInjectInto(); while (! result.success && parent) { injectIntoCords = parent.getCoordinates(); if (injectIntoCords.top < 0) { parent = body; continue; } pointCords = this.pointTo.getCoordinates(parent); if (this.options.forcePosition) { maxHeight = this._getMaxHeightWhenForcePosition(injectIntoCords, pointCords, positionNumber); if (maxHeight > 0) { this.html.setStyle('max-height', maxHeight); } } injectScroll = parent.getScroll(); pointCords.left += injectScroll.x; pointCords.top += injectScroll.y; currentLoopIndex = 0; // do it while ( ! result.success && positionNumbers.length > currentLoopIndex) { result = this._testPosition(positionNumbers[currentLoopIndex].point, popoverDimensions, pointCords, injectIntoCords, injectScroll); currentLoopIndex += 1; } if (parent == body && this.options.forcePosition) { popoverDimensions.height = popoverDimensions.height < maxHeight ? popoverDimensions.height : maxHeight; result = this._testPosition(positionNumber, popoverDimensions, pointCords, injectIntoCords, injectScroll); result.success = true; } if (result.success) { break; } if (parent !== body) { parent = parent.getParent(); } else { break; } } if (result.success) { parent.grab(this.html); } } // handle no good calculated position if ( ! result.success) { body.grab(this.html); var center = this.html.position({ relativeTo: body ,position: 'center' ,offset: this.offset ,returnPos: true }); result.left = center.left; result.top = center.top; this.showNipple = false; } if (this.showNipple) { this._addNipple(result.edgeNumber, result, popoverDimensions); } //console.log(result); this._displayPopover(result.left, result.top); } ,_doModal: function() { this._computeDimensions(); this.html.setStyles(Object.merge({ height: this.height ,width: this.width ,'max-height': this.windowCoordinates.height-25 ,'max-width': this.windowCoordinates.width-25 ,opacity: 0 ,visibility: 'hidden' ,display: 'block' }, this.options.styles)); // if we're positioning relative to another element if (this.options.relativeTo) { this.centerPoint = this.html.position({relativeTo: this.options.relativeTo, position: this.options.position, edge: this.options.edge, offset: this.offset}); } else { this.centerPoint = this.html.position({relativeTo: this.targetElement, position:'center', offset: this.offset}); } this.html.fade('in'); } ,_addNipple: function(edgeNumber, result, popoverDimensions) { this.html.grab( this.nipple = new Element('div', { 'class':'MDPopoverNipple' ,styles: { position:'absolute' ,'z-index':this.zIndex+50 } }) ); ['Top', 'Bottom', 'Right', 'Left'].each(function(className) { this.html.removeClass(className); }, this); switch (edgeNumber) { case 1: this.html.addClass('Bottom'); this.nipple.setStyles({ top: -20 ,left: 10 + this.offset.x }); break; case 2: this.html.addClass('Bottom'); this.nipple.setStyles({ top: -20 ,left: ((popoverDimensions.width/2) - 10) - this.offset.x }); break; case 3: this.html.addClass('Bottom'); this.nipple.setStyles({ top: -20 ,left: (popoverDimensions.width - 30) - this.offset.x }); break; case 4: this.html.addClass('Left'); this.nipple.setStyles({ top: (popoverDimensions.height/2) - 10 ,left: (popoverDimensions.width) - this.offset.x }); break; case 5: this.html.addClass('Top'); this.nipple.setStyles({ top: popoverDimensions.height ,left: (popoverDimensions.width - 30) - this.offset.x }); break; case 6: this.html.addClass('Top'); this.nipple.setStyles({ top: popoverDimensions.height ,left: ((popoverDimensions.width/2) - 10) - this.offset.x }); break; case 7: this.html.addClass('Top'); this.nipple.setStyles({ top: popoverDimensions.height ,left: 10 - this.offset.x }); break; case 8: this.html.addClass('Right'); this.nipple.setStyles({ top: (popoverDimensions.height/2) - 10 ,left: -20 - this.offset.x }); break; } } ,_getPositionNumbersToTest: function(originalNumber, pointCords) { // length between each positionNumber 1 => 2, 2 => 3 var lengths = { 1: pointCords.width/2 ,2: pointCords.width/2 ,3: pointCords.height/2 ,4: pointCords.height/2 ,5: pointCords.width/2 ,6: pointCords.width/2 ,7: pointCords.height/2 ,8: pointCords.height/2 }; function calcLeft(point, originalNumber) { return calcRight(originalNumber, point); } function calcRight(point, stop) { var toReturn = 0; while (point != stop) { toReturn += lengths[point]; point += 1; if (point > 8) { point = 1; } } return toReturn; } // distances from each point to the original var distances = []; var left, right; for (var i = 1; i <= 8; i++) { left = calcLeft(i, originalNumber); right = calcRight(i, originalNumber); distances.push({ point: i ,distance: left < right ? left : right }); } distances.sort(function(a, b) { if (a.distance === 0) { return -1; } if (b.distance === 0) { return 1; } if (a.distance == b.distance) { return a.point > b.point ? -1 : 1; } return a.distance > b.distance ? -1 : 1; }); return distances; } ,_testPosition: function(positionNumber, popoverDimensionsOrig, pointCords, viewContextCords, injectScroll) { var toReturn = {success: true, position: positionNumber}; var offset = { x: this.offset.x ,y: this.offset.y }; var popoverDimensions = { width: popoverDimensionsOrig.width ,height: popoverDimensionsOrig.height }; if (typeof popoverDimensions.width === 'string') { popoverDimensions.width = popoverDimensions.width.replace(/(px|pt|em)$/g, '').toInt(10); } if (typeof popoverDimensions.height === 'string') { popoverDimensions.height = popoverDimensions.height.replace(/(px|pt|em)$/g, '').toInt(10); } var edgeNumber = positionoptions[this.edge.toLowerCase()] || 'auto'; edgeNumber = (function() { if (edgeNumber === 'auto') { switch (positionNumber) { case 1: return 5; case 2: return 6; case 3: return 7; case 4: return 8; case 5: return 1; case 6: return 2; case 7: return 3; case 8: return 4; default: return 1; } } else { return edgeNumber; } }()); toReturn.edgeNumber = edgeNumber; // for the left attribute switch (positionNumber) { case 1: // topLeft switch (edgeNumber) { case 1: toReturn.top = pointCords.top; toReturn.left = pointCords.left; break; case 2: toReturn.left = pointCords.left - (popoverDimensions.width/2); toReturn.top = pointCords.top; break; case 3: toReturn.left = pointCords.left - popoverDimensions.width; toReturn.top = pointCords.top; break; case 4: toReturn.left = pointCords.left - popoverDimensions.width; toReturn.top = pointCords.top - popoverDimensions.height/2; break; case 5: toReturn.left = pointCords.left - popoverDimensions.width; toReturn.top = pointCords.top - popoverDimensions.height; break; case 6: toReturn.left = pointCords.left - (popoverDimensions.width/2); toReturn.top = pointCords.top - popoverDimensions.height; break; case 7: toReturn.left = pointCords.left; toReturn.top = pointCords.top - popoverDimensions.height; break; case 8: toReturn.top = pointCords.top - popoverDimensions.height/2; toReturn.left = pointCords.left; break; } break; case 2: switch (edgeNumber) { case 1: toReturn.left = (pointCords.left + pointCords.width/2); toReturn.top = pointCords.top; break; case 2: toReturn.left = (pointCords.left + pointCords.width/2) - (popoverDimensions.width/2); toReturn.top = pointCords.top; break; case 3: toReturn.left = (pointCords.left + pointCords.width/2) - popoverDimensions.width ; toReturn.top = pointCords.top; break; case 4: toReturn.left = (pointCords.left + pointCords.width/2) - popoverDimensions.width; toReturn.top = pointCords.top - popoverDimensions.height/2; break; case 5: toReturn.left = (pointCords.left + pointCords.width/2) - popoverDimensions.width; toReturn.top = pointCords.top - popoverDimensions.height; break; case 6: toReturn.left = (pointCords.left + pointCords.width/2) - (popoverDimensions.width/2); toReturn.top = pointCords.top - popoverDimensions.height; break; case 7: toReturn.left = (pointCords.left + pointCords.width/2) - 20; toReturn.top = pointCords.top - popoverDimensions.height; break; case 8: toReturn.left = (pointCords.left + pointCords.width/2); toReturn.top = pointCords.top - popoverDimensions.height/2; break; } break; case 3: // bottomRight switch (edgeNumber) { case 1: toReturn.left = (pointCords.left + pointCords.width); toReturn.top = pointCords.top; break; case 2: toReturn.left = (pointCords.left + pointCords.width) - (popoverDimensions.width/2); toReturn.top = pointCords.top; break; case 3: toReturn.left = (pointCords.left + pointCords.width) - popoverDimensions.width ; toReturn.top = pointCords.top; break; case 4: toReturn.left = (pointCords.left + pointCords.width) - popoverDimensions.width; toReturn.top = pointCords.top - popoverDimensions.height/2; break; case 5: toReturn.left = (pointCords.left + pointCords.width) - popoverDimensions.width ; toReturn.top = pointCords.top - popoverDimensions.height; break; case 6: toReturn.left = (pointCords.left + pointCords.width) - (popoverDimensions.width/2); toReturn.top = pointCords.top - popoverDimensions.height; break; case 7: toReturn.left = (pointCords.left + pointCords.width) - 20; toReturn.top = pointCords.top - popoverDimensions.height; break; case 8: toReturn.left = (pointCords.left + pointCords.width); toReturn.top = pointCords.top - popoverDimensions.height/2; break; } break; case 4: // bottomRight switch (edgeNumber) { case 1: toReturn.left = (pointCords.left + pointCords.width); toReturn.top = (pointCords.top + pointCords.height/2); break; case 2: toReturn.left = (pointCords.left + pointCords.width) - (popoverDimensions.width/2); toReturn.top = (pointCords.top + pointCords.height/2); break; case 3: toReturn.left = (pointCords.left + pointCords.width) - popoverDimensions.width ; toReturn.top = (pointCords.top + pointCords.height/2); break; case 4: toReturn.left = (pointCords.left + pointCords.width) - popoverDimensions.width; toReturn.top = (pointCords.top + pointCords.height/2) - popoverDimensions.height/2; break; case 5: toReturn.left = (pointCords.left + pointCords.width) - popoverDimensions.width ; toReturn.top = (pointCords.top + pointCords.height/2)- popoverDimensions.height; break; case 6: toReturn.left = (pointCords.left + pointCords.width) - (popoverDimensions.width/2); toReturn.top = (pointCords.top + pointCords.height/2)- popoverDimensions.height; break; case 7: toReturn.left = (pointCords.left + pointCords.width) ; toReturn.top = (pointCords.top + pointCords.height/2)- popoverDimensions.height; break; case 8: toReturn.left = (pointCords.left + pointCords.width); toReturn.top = (pointCords.top + pointCords.height/2) - popoverDimensions.height/2; break; } break; case 5: // bottomRight switch (edgeNumber) { case 1: toReturn.left = (pointCords.left + pointCords.width); toReturn.top = (pointCords.top + pointCords.height); break; case 2: toReturn.left = (pointCords.left + pointCords.width) - (popoverDimensions.width/2); toReturn.top = (pointCords.top + pointCords.height); break; case 3: toReturn.left = (pointCords.left + pointCords.width) - popoverDimensions.width; toReturn.top = (pointCords.top + pointCords.height); break; case 4: toReturn.left = (pointCords.left + pointCords.width) - popoverDimensions.width; toReturn.top = (pointCords.top + pointCords.height) - popoverDimensions.height/2; break; case 5: toReturn.left = (pointCords.left + pointCords.width) - popoverDimensions.width; toReturn.top = (pointCords.top + pointCords.height)- popoverDimensions.height; break; case 6: toReturn.left = (pointCords.left + pointCords.width) - (popoverDimensions.width/2); toReturn.top = (pointCords.top + pointCords.height)- popoverDimensions.height; break; case 7: toReturn.left = (pointCords.left + pointCords.width) - 20; toReturn.top = (pointCords.top + pointCords.height)- popoverDimensions.height; break; case 8: toReturn.left = (pointCords.left + pointCords.width); toReturn.top = (pointCords.top + pointCords.height) - popoverDimensions.height/2; break; } break; case 6: switch (edgeNumber) { case 1: toReturn.left = (pointCords.left + pointCords.width/2); toReturn.top = (pointCords.top + pointCords.height); break; case 2: toReturn.left = (pointCords.left + pointCords.width/2) - (popoverDimensions.width/2); toReturn.top = (pointCords.top + pointCords.height); break; case 3: toReturn.left = (pointCords.left + pointCords.width/2) - popoverDimensions.width ; toReturn.top = (pointCords.top + pointCords.height); break; case 4: toReturn.left = (pointCords.left + pointCords.width/2) - popoverDimensions.width; toReturn.top = (pointCords.top + pointCords.height) - popoverDimensions.height/2; break; case 5: toReturn.left = (pointCords.left + pointCords.width/2) - popoverDimensions.width; toReturn.top = (pointCords.top + pointCords.height)- popoverDimensions.height; break; case 6: toReturn.left = (pointCords.left + pointCords.width/2) - (popoverDimensions.width/2); toReturn.top = (pointCords.top + pointCords.height)- popoverDimensions.height; break; case 7: toReturn.left = (pointCords.left + pointCords.width/2) - 20; toReturn.top = (pointCords.top + pointCords.height)- popoverDimensions.height; break; case 8: toReturn.left = (pointCords.left + pointCords.width/2); toReturn.top = (pointCords.top + pointCords.height) - popoverDimensions.height/2; break; } break; case 7: // topLeft switch (edgeNumber) { case 1: toReturn.left = pointCords.left; toReturn.top = (pointCords.top + pointCords.height); break; case 2: toReturn.left = pointCords.left - (popoverDimensions.width/2); toReturn.top = (pointCords.top + pointCords.height); break; case 3: toReturn.left = pointCords.left - popoverDimensions.width + 30; toReturn.top = (pointCords.top + pointCords.height); break; case 4: toReturn.left = pointCords.left - popoverDimensions.width; toReturn.top = (pointCords.top + pointCords.height) - popoverDimensions.height/2; break; case 5: toReturn.left = pointCords.left - popoverDimensions.width + 20; toReturn.top = (pointCords.top + pointCords.height)- popoverDimensions.height; break; case 6: toReturn.left = pointCords.left - (popoverDimensions.width/2); toReturn.top = (pointCords.top + pointCords.height)- popoverDimensions.height; break; case 7: toReturn.left = pointCords.left - 20; toReturn.top = (pointCords.top + pointCords.height)- popoverDimensions.height; break; case 8: toReturn.left = pointCords.left; toReturn.top = (pointCords.top + pointCords.height) - popoverDimensions.height/2; break; } break; case 8: // topLeft switch (edgeNumber) { case 1: toReturn.left = pointCords.left; toReturn.top = (pointCords.top + pointCords.height/2); break; case 2: toReturn.left = pointCords.left - (popoverDimensions.width/2); toReturn.top = (pointCords.top + pointCords.height/2); break; case 3: toReturn.left = pointCords.left - popoverDimensions.width + 30; toReturn.top = (pointCords.top + pointCords.height/2); break; case 4: toReturn.left = pointCords.left - popoverDimensions.width; toReturn.top = (pointCords.top + pointCords.height/2) - popoverDimensions.height/2; break; case 5: toReturn.left = pointCords.left - popoverDimensions.width + 20; toReturn.top = (pointCords.top + pointCords.height/2)- popoverDimensions.height; break; case 6: toReturn.left = pointCords.left - (popoverDimensions.width/2); toReturn.top = (pointCords.top + pointCords.height/2)- popoverDimensions.height; break; case 7: toReturn.left = pointCords.left - 20; toReturn.top = (pointCords.top + pointCords.height/2)- popoverDimensions.height; break; case 8: toReturn.left = pointCords.left; toReturn.top = (pointCords.top + pointCords.height/2) - popoverDimensions.height/2; break; } break; } if (this.showNipple) { switch (edgeNumber) { case 1: offset.x -= 20; // offset.y += 20; break; case 2: offset.x += 0; offset.y += 20; break; case 3: offset.x += 20; // offset.y += 20; break; case 4: offset.x -= 20; offset.y += 0; break; case 5: offset.x += 20; // offset.y -= 20; break; case 6: offset.x += 0; offset.y -= 20; break; case 7: offset.x -= 20; // offset.y -= 20; break; case 8: offset.x += 20; offset.y -= 0; break; } } toReturn.left += offset.x; toReturn.top += offset.y; var lengthFromLeft = toReturn.left - injectScroll.x; var lengthFromRight = viewContextCords.width - (lengthFromLeft + popoverDimensions.width) ;//+ injectScroll.x/2; if (lengthFromLeft < 0 || 0 > lengthFromRight) { toReturn.success = false; } var lengthFromTop = toReturn.top - injectScroll.y; var lengthFromBottom = viewContextCords.height - (lengthFromTop + popoverDimensions.height) ;//+ injectScroll.y/2; if (toReturn.success && (lengthFromTop < 0 || 0 > lengthFromBottom)) { toReturn.success = false; } return toReturn; } ,_displayPopover: function(left, top) { this.html.setStyles({ display: 'block' ,left: left ,top: top }); this.html.fade('in'); } ,_computeDimensions: function() { this.windowCoordinates = window.getCoordinates(); // Determine this.contentSize ... by recreating the popover and it's contents, injecting it invisibly into the body, measuring it, and then deleting it. if (this.content) { var contentTempInner, contentTemp; contentTemp = new Element('div', { 'class': this.html.get('class') ,styles: { position: 'static' ,width: (this.options.width ? this.options.width : 'auto') } }).grab( contentTempInner = new Element('div', { 'class':this.contentContainer.get('class') ,styles: { position: 'static' ,display: 'inline-block' } }).adopt( this.contentContainer.clone().getChildren() ) ); (this.options.injectInto ? this.options.injectInto : (this.options.maskTarget ? this.options.maskTarget : this._getInjectInto() ) ).grab(contentTemp); this.renderedSize = contentTemp.getDimensions(true); this.contentSize = contentTempInner.getDimensions(true); this.renderedSize.height = this.contentSize.height; contentTemp.destroy(); } // Set basic dimentions... this.height = (this.options.height || this.contentSize.height); this.width = (this.options.width || this.contentSize.width+2); if (this.options.minWidth) { this.width = this.width > this.options.minWidth ? this.width : this.options.minWidth; } if (typeof this.width === 'string') { this.width = this.width.replace(/(px|pt|em)$/g, '').toInt(10); } if (typeof this.height === 'string') { this.height = this.height.replace(/(px|pt|em)$/g, '').toInt(10); } return { width: this.width ,height: this.height }; } ,_getInjectInto: function() { if ( ! this.injectInto) { if (this.options.injectInto) { this.injectInto = this.options.injectInto; } else if (! this.pointTo) { this.injectInto = $$('body')[0]; } else { var node = this.pointTo.getParent(); while ( ! MD.isScrollable(node) && node) { node = node.getParent(); } if ( ! node || node.tagName === 'HTML') { node = $$('body')[0]; } this.injectInto = node; } } return this.injectInto; } ,complete: function(){ // Fire the onComplete event this.fireEvent('complete', [this.html, this.referenceElement], 150); } ,hide: function(suppressOnHideEvent){ if (suppressOnHideEvent !== false) {// so that we can suppress the onHide event if we need to. this.fireEvent('hide', [this.contentContainer, this]); } if (this.mask) { this.mask.hide(); } if (this.html) { this.html.setStyles({ visibility: 'hidden' ,opacity: 0 ,display: 'none' }); } if (this.options.destroyOnHide) { try { (function(){ if (this.html) { this.destroy(); } }.bind(this)).delay(240); } catch(error){ console.error(error); } } else { // Add the event(s) to close if (this.options.clickOutsideToClose && this.html) { this.html.removeEvent('clickout', this._clickoutFunction); } } if (!this.options.destroyOnHide && this.options.closeButton) { this.closeButton.toElement().hide(); } // Remove this Popover from the stack if (MD.PopoverStack.length) { var indexInStack = false; MD.PopoverStack.some(function(item, ind) { if (item.id == this.id) { indexInStack = ind; return true; } return false; }, this); if ( indexInStack !== false) { MD.PopoverStack.splice(indexInStack, 1); } } this.showing = false; this.fireEvent('hide:after', this); return this; } ,destroy: function(){ if (this.options.destroyContent) { // var el = this.html.getElements('*'); // if (el && el.length) { // el.destroy(); // } } else { this.setContent(new Element('div')); } if (this.html) { this.html.destroy(); delete this.html; } if (this.mask) { this.mask.destroy(); delete this.mask; } } ,changeSize: function(dimensions){ this.html.morph({ height:dimensions.height || this.options.height ,width:dimensions.width || this.options.width }); } ,setContent: function(content){ this.content = content; document.id(this.contentContainer).empty(); MD.setContent(content, this.contentContainer); return this; } ,toElement: function(){ return this.html; } ,isActive: function() { return this.showing; } ,_getSpinnerElement: function() { return this.contentContainer; } }); MD.Popover.KillAll = function(includingExclusiveImmunes){ if (MD.PopoverStack && MD.PopoverStack.length) { var i; for (i = MD.PopoverStack.length - 1 ;i >= 0; i -=1) { if ( ! MD.PopoverStack[i].exclusiveImmune || includingExclusiveImmunes) { MD.PopoverStack[i].hide(); } } } }; }(MD));