| 1 |
/* |
| 2 |
* jquery-gpopover |
| 3 |
* http://github.com/markembling/jquery-gpopover |
| 4 |
* |
| 5 |
* A simple jQuery plugin for creating popover elements similar to Google's |
| 6 |
* new 'apps' launcher/switcher. |
| 7 |
* |
| 8 |
* Copyright (c) 2013 Mark Embling (markembling.info) |
| 9 |
* Licensed under the BSD (3 clause) license. |
| 10 |
*/ |
| 11 |
|
| 12 |
;(function($){ |
| 13 |
|
| 14 |
var GPopover = function(element, options) { |
| 15 |
this.options = null; |
| 16 |
this.$trigger = null; |
| 17 |
this.$popover = null; |
| 18 |
|
| 19 |
this.init(element, options); |
| 20 |
} |
| 21 |
|
| 22 |
GPopover.prototype.init = function(element, options) { |
| 23 |
var that = this; |
| 24 |
|
| 25 |
this.options = $.extend({}, $.fn.gpopover.defaults, options); |
| 26 |
|
| 27 |
this.$trigger = $(element); |
| 28 |
this.$popover = $('#' + this.$trigger.data('popover')); |
| 29 |
|
| 30 |
this._addArrowElements(); |
| 31 |
|
| 32 |
if (this.options.preventHide) { |
| 33 |
this._preventHideClickPropagation(); |
| 34 |
} |
| 35 |
|
| 36 |
this.$trigger.click(function(e){ |
| 37 |
if (! that.$popover.is(":visible")) { |
| 38 |
// Trigger a click on the parent element (that can bubble up) |
| 39 |
$(this).parent().click(); |
| 40 |
|
| 41 |
that.show(); |
| 42 |
|
| 43 |
e.stopPropagation(); |
| 44 |
} |
| 45 |
|
| 46 |
e.preventDefault(); |
| 47 |
}); |
| 48 |
} |
| 49 |
|
| 50 |
GPopover.prototype.show = function() { |
| 51 |
var that = this; |
| 52 |
|
| 53 |
// Set width before showing |
| 54 |
this.$popover.width(this.options.width); |
| 55 |
|
| 56 |
// Show the popover |
| 57 |
this.$popover.fadeIn(this.options.fadeInDuration); |
| 58 |
|
| 59 |
// Set up hiding |
| 60 |
$(document).one('click.popoverHide', function() { |
| 61 |
// _hidePopover($popover, settings); |
| 62 |
that.hide(); |
| 63 |
}); |
| 64 |
|
| 65 |
// Sort out the position (must be done after showing) |
| 66 |
var triggerPos = this.$trigger.offset(); |
| 67 |
this.$popover.offset({ |
| 68 |
left: (triggerPos.left + (this.$trigger.outerWidth() / 2)) - (this.$popover.outerWidth() / 2), |
| 69 |
top: triggerPos.top + this.$trigger.outerHeight() + 10 |
| 70 |
// the final 10 above allows room for the arrow above it |
| 71 |
}); |
| 72 |
|
| 73 |
// Check and reposition if out of the viewport |
| 74 |
var positionXCorrection = this._repositionForViewportSides(); |
| 75 |
|
| 76 |
// Set the position of the arrow elements |
| 77 |
this._setArrowPosition(positionXCorrection); |
| 78 |
|
| 79 |
// Call the callback |
| 80 |
this.options.onShow.call(this.$trigger, this.$popover); |
| 81 |
} |
| 82 |
|
| 83 |
GPopover.prototype.hide = function() { |
| 84 |
// Hide the popover |
| 85 |
this.$popover.fadeOut(this.options.fadeOutDuration); |
| 86 |
|
| 87 |
// Call the callback |
| 88 |
this.options.onHide.call(this.$trigger, this.$popover); |
| 89 |
} |
| 90 |
|
| 91 |
GPopover.prototype._addArrowElements = function() { |
| 92 |
this.$arrow = $('<div class="gpopover-arrow"></div>'); |
| 93 |
this.$arrowShadow = $('<div class="gpopover-arrow-shadow"></div>'); |
| 94 |
|
| 95 |
this.$popover.append(this.$arrow); |
| 96 |
this.$popover.append(this.$arrowShadow); |
| 97 |
} |
| 98 |
|
| 99 |
GPopover.prototype._preventHideClickPropagation = function() { |
| 100 |
/* Prevent clicks within the popover from being propagated |
| 101 |
to the document (and thus stop the popover from being |
| 102 |
hidden) */ |
| 103 |
this.$popover.click(function(e) { e.stopPropagation(); }); |
| 104 |
} |
| 105 |
|
| 106 |
GPopover.prototype._repositionForViewportSides = function() { |
| 107 |
var popoverOffsetLeft = this.$popover.offset().left, |
| 108 |
positionXCorrection = 0, |
| 109 |
$window = $(window); |
| 110 |
|
| 111 |
// Right edge |
| 112 |
if (popoverOffsetLeft + this.$popover.outerWidth() + this.options.viewportSideMargin > $window.width()) { |
| 113 |
var rightEdgeCorrection = -((popoverOffsetLeft + this.$popover.outerWidth() + this.options.viewportSideMargin) - $window.width()); |
| 114 |
popoverOffsetLeft = popoverOffsetLeft + rightEdgeCorrection |
| 115 |
|
| 116 |
positionXCorrection = rightEdgeCorrection; |
| 117 |
} |
| 118 |
|
| 119 |
// Left edge |
| 120 |
if (popoverOffsetLeft < this.options.viewportSideMargin) { |
| 121 |
var leftEdgeCorrection = this.options.viewportSideMargin - popoverOffsetLeft; |
| 122 |
popoverOffsetLeft = popoverOffsetLeft + leftEdgeCorrection |
| 123 |
|
| 124 |
positionXCorrection += leftEdgeCorrection; |
| 125 |
} |
| 126 |
|
| 127 |
// Reposition the popover element if necessary |
| 128 |
if (positionXCorrection !== 0) { |
| 129 |
this.$popover.offset({ left: popoverOffsetLeft }); |
| 130 |
} |
| 131 |
|
| 132 |
return positionXCorrection; |
| 133 |
} |
| 134 |
|
| 135 |
GPopover.prototype._setArrowPosition = function(positionXCorrection) { |
| 136 |
var leftPosition = (this.$popover.outerWidth() / 2) - (this.$arrow.outerWidth() / 2) - positionXCorrection; |
| 137 |
|
| 138 |
this.$arrow.css({ top: -7, left: leftPosition }); |
| 139 |
this.$arrowShadow.css({ top: -8, left: leftPosition }); |
| 140 |
} |
| 141 |
|
| 142 |
$.fn.gpopover = function(option) { |
| 143 |
return this.each(function(){ |
| 144 |
var $this = $(this), |
| 145 |
data = $this.data('gpopover'), |
| 146 |
options = (typeof option == 'object' && option); |
| 147 |
|
| 148 |
// Initialise if not already done |
| 149 |
if (!data) { |
| 150 |
data = new GPopover(this, options); |
| 151 |
$this.data('gpopover', data); |
| 152 |
} |
| 153 |
|
| 154 |
// If the option parameter was a string, trigger the named function |
| 155 |
if (typeof option == 'string') data[option](); |
| 156 |
}); |
| 157 |
|
| 158 |
}; |
| 159 |
|
| 160 |
// Default settings |
| 161 |
$.fn.gpopover.defaults = { |
| 162 |
width: 250, // Width of the popover |
| 163 |
fadeInDuration: 65, // Duration of popover fade-in animation |
| 164 |
fadeOutDuration: 65, // Duration of popover fade-out animation |
| 165 |
viewportSideMargin: 10, // Space to leave the side if out the viewport |
| 166 |
preventHide: false, // Prevent hide when clicking within popover |
| 167 |
|
| 168 |
onShow: function() {}, // Called upon showing the popover |
| 169 |
onHide: function() {} // Called upon hiding the popover |
| 170 |
}; |
| 171 |
|
| 172 |
})(jQuery); |
| 173 |
|