/************************************************************************************
DevPortal Navigation Popover This is a custom popover for the desktop version of the devportal menu. It is unique in two ways. 1. It allows you to specify a screen size below which the popover will not appear. This allows us to do something different for mobile. 2. It allows you to hover over the modal and click on a link in the body of the popover.
**************************************************************************************/ P.when(“jQuery”).register(“jquery-placeholder”, function ($) {
'use strict'; // NAV POPOVER PUBLIC CLASS DEFINITION // =============================== var DPNavbarPopover = function (element, options) { this.options = null; this.timeout = null; this.hoverState = null; this.$element = null; this.init(element, options); } DPNavbarPopover.TRANSITION_DURATION = 150; DPNavbarPopover.DEFAULTS = { animation: true, minWindowWidth: 1000, template: '<div class="dp-navbar-popover">' + '<div class="dp-navbar-popover-arrow"></div>' + '<div class="dp-navbar-popover-content"></div>' + '</div>', trigger: 'hover focus', delay: 0, html: false, content: '' } DPNavbarPopover.prototype.init = function (element, options) { this.$element = $(element); this.options = this.getOptions(options); var triggers = this.options.trigger.split(' '); for (var i = triggers.length; i--;) { var trigger = triggers[i]; if (trigger === 'click') { this.$element.click($.proxy(this.toggle, this)); } else if (trigger !== 'manual') { if (trigger === 'hover') { this.$element.mouseenter($.proxy(this.enter, this)); this.$element.mouseleave($.proxy(this.leave, this)); } else { this.$element.focusin($.proxy(this.enter, this)); this.$element.focusout($.proxy(this.leave, this)); } } } } DPNavbarPopover.prototype.getDefaults = function () { return DPNavbarPopover.DEFAULTS; } DPNavbarPopover.prototype.getOptions = function (options) { options = $.extend({}, this.getDefaults(), this.$element.data(), options); if (options.delay && typeof options.delay === 'number') { var delay = options.delay; options.delay = { show: delay, hide: delay }; } return options; } DPNavbarPopover.prototype.enter = function () { var self = this; if (window.innerWidth > self.options.minWindowWidth) { if (self.$popover && self.$popover.is(':visible')) { self.hoverState = 'in'; return; } clearTimeout(self.timeout); self.hoverState = 'in'; if (!self.options.delay || !self.options.delay.show) { return self.show(); } self.timeout = setTimeout(function () { if (self.hoverState === 'in') { self.show(); } }, self.options.delay.show); } } DPNavbarPopover.prototype.leave = function (event) { var self = this; var container; clearTimeout(self.timeout); self.hoverState = 'out'; if (!self.options.delay || !self.options.delay.hide) { return self.hide(); } self.timeout = setTimeout(function () { if (self.hoverState === 'out') { self.hide(); } }, self.options.delay.hide); if (event.currentTarget) { container = $(event.currentTarget).siblings('.dp-navbar-popover'); container.one('mouseenter', function() { clearTimeout(self.timeout); container.one('mouseleave', function(event) { // This recursive call caused an unresponsive script // warning dialog. Changing to hide() fixed that and doesn't // appear to have any negative effects. //self.leave(event); self.hide(); }); }); } } DPNavbarPopover.prototype.show = function () { // What does this do? var e = $.Event('show.dp.nav.popover'); this.$element.trigger(e) if (this.hasContent()) { var inDom = $.contains(this.$element[0].ownerDocument.documentElement, this.$element[0]) if (e.isDefaultPrevented() || !inDom) { return; } var that = this; var $popover = this.popover(); var tipId = this.getUID(); this.setContent(); $popover.attr('id', tipId); this.$element.attr('aria-describedby', tipId); if (this.options.animation) { $popover.addClass('fade'); } $popover .detach() .css({ top: 0, left: 0, display: 'block' }) .data('dp.navbar.popover', this); $popover.insertAfter(this.$element) var pos = this.getPosition(); var offset = { top: pos.top + pos.height, left: pos.left }; this.applyPlacement(offset); var complete = function () { var prevHoverState = that.hoverState; that.$element.trigger('shown.bs.' + that.type); that.hoverState = null; if (prevHoverState === 'out') { that.leave(that); } } if ($.support.transition && this.$popover.hasClass('fade')) { $popover .one('bsTransitionEnd', complete) .emulateTransitionEnd(DPNavbarPopover.TRANSITION_DURATION); } else { complete(); } } } DPNavbarPopover.prototype.applyPlacement = function (offset, placement) { var $popover = this.popover(); var elWidth = this.$element[0].offsetWidth; var arrowOffset = (elWidth / 2) - 11; offset.top = offset.top + 10; offset.left = offset.left; $popover.addClass('in'); $popover.offset(offset); this.arrow().css('margin-left', arrowOffset + 'px') } DPNavbarPopover.prototype.hasContent = function () { return this.getContent(); } DPNavbarPopover.prototype.getContent = function () { if (this.$element.attr('data-content')) { return this.$element.attr('data-content'); } else { if (typeof this.options.content === 'function') { return this.options.content.call(this.$element[0]); } else { return this.options.content; } } } DPNavbarPopover.prototype.setContent = function () { var $popover = this.popover(); var content = this.getContent(); $popover.find('.dp-navbar-popover-content').children().detach().end()[ // we use append for html objects to maintain js events this.options.html ? (typeof content === 'string' ? 'html' : 'append') : 'text' ](content) $popover.removeClass('fade top bottom left right in') } DPNavbarPopover.prototype.hide = function (callback) { var that = this; var $popover = this.popover(); var e = $.Event('hide.dp.nav.popover'); function complete() { $popover.fadeOut(); if (that.hoverState !== 'in') { $popover.detach() } that.$element .removeAttr('aria-describedby') .trigger('hidden.dp.nav.popover') if (callback) { callback(); } } this.$element.trigger(e); if (e.isDefaultPrevented()) { return; } $popover.removeClass('in');
// Removed the transition logic as it resulted in menus that never disappeared. // // if ($.support.transition && this.$popover.hasClass('fade')) { // $popover // .one('bsTransitionEnd', complete) // .emulateTransitionEnd(DPNavbarPopover.TRANSITION_DURATION) // } else {
complete();
// }
this.hoverState = null; return this; } DPNavbarPopover.prototype.hasContent = function () { return this.getContent(); } DPNavbarPopover.prototype.getPosition = function ($element) { $element = $element || this.$element; var el = $element[0]; var elRect = el.getBoundingClientRect() if (elRect.width === null) { // width and height are missing in IE8, so compute them manually; see https://github.com/twbs/bootstrap/issues/14093 elRect = $.extend({}, elRect, { width: elRect.right - elRect.left, height: elRect.bottom - elRect.top }) } var elOffset = $element.offset() return $.extend({}, elRect, elOffset); } DPNavbarPopover.prototype.getUID = function () { var UID = Math.round(Math.random() * 1000000); return 'dp-navbar-popover-' + UID; } DPNavbarPopover.prototype.popover = function () { if (!this.$popover) { this.$popover = $(this.options.template); } return this.$popover } DPNavbarPopover.prototype.arrow = function () { if (!this.$arrow) { this.$arrow = this.popover().find('.dp-navbar-popover-arrow'); } return this.$arrow; } DPNavbarPopover.prototype.toggle = function (e) { var self = this if (e) { self = $(e.currentTarget).data('dp.navbar.popover') } self.popover().hasClass('in') ? self.leave(self) : self.enter(self) } // Added for debugging DPNavbarPopover.prototype.getMenuName = function () { return this.$element.find("a.dp-navbar-button").text().trim(); } // TOOLTIP PLUGIN DEFINITION // ========================= function Plugin(option) { return this.each(function () { var $this = $(this); var data = $this.data('dp.navbar.popover'); var options = typeof option === 'object' && option; if (!data && option === 'destroy') { return; } if (!data) { $this.data('dp.navbar.popover', (data = new DPNavbarPopover(this, options))); } if (typeof option === 'string') { data[option](); } }) } var old = $.fn.dpNavbarPopover $.fn.dpNavbarPopover = Plugin $.fn.dpNavbarPopover.Constructor = DPNavbarPopover // CSS TRANSITION SUPPORT (Shoutout: http://www.modernizr.com/) // ============================================================ function transitionEnd() { var el = document.createElement('bootstrap') var transEndEventNames = { WebkitTransition : 'webkitTransitionEnd', MozTransition : 'transitionend', OTransition : 'oTransitionEnd otransitionend', transition : 'transitionend' } for (var name in transEndEventNames) { if (el.style[name] !== undefined) { return { end: transEndEventNames[name] } } } return false; // explicit for ie8 (._.) } // http://blog.alexmaccaw.com/css-transitions $.fn.emulateTransitionEnd = function (duration) { var called = false var $el = this $(this).one('bsTransitionEnd', function () { called = true; }) var callback = function () { if (!called) { $($el).trigger($.support.transition.end); } } setTimeout(callback, duration); return this; } $(function () { $.support.transition = transitionEnd(); if (!$.support.transition) { return; } $.event.special.bsTransitionEnd = { bindType: $.support.transition.end, delegateType: $.support.transition.end, handle: function (e) { if ($(e.target).is(this)) { return e.handleObj.handler.apply(this, arguments); } } } })
});